[PATCH 1/2] fix(attestation): strip credentials also if token is used

1 view
Skip to first unread message

Felix Moessbauer

unread,
Apr 29, 2026, 3:18:22 AM (11 days ago) Apr 29
to kas-...@googlegroups.com, jan.k...@siemens.com, Felix Moessbauer, Keyvan Hardani
When using a credential that just consists of a username (commonly used
for tokens), we currently do not strip it as the code only handles the
username:password case correctly. By that, token might be leaked into
the attestation data.

We fix this by manually reconstructing the URL that is added to the
attestation data and leave out the credential part.

Reported-by: Keyvan Hardani <keyvan....@ieee.org>
Fixes: 3e5b0c20a ("add support to create provenance build attestations")
Signed-off-by: Felix Moessbauer <felix.mo...@siemens.com>
---
kas/attestation.py | 18 +++++++++++-------
1 file changed, 11 insertions(+), 7 deletions(-)

diff --git a/kas/attestation.py b/kas/attestation.py
index e2d764be0..abfe06c36 100644
--- a/kas/attestation.py
+++ b/kas/attestation.py
@@ -31,7 +31,7 @@ import hashlib
import base64
import sys
from enum import Enum
-from urllib.parse import urlparse
+from urllib.parse import urlparse, urlunparse
from pathlib import Path
from datetime import datetime, timezone
from kas import __version__ as KASVERSION
@@ -89,14 +89,18 @@ class Provenance:
@staticmethod
def _strip_credentials(url):
"""
- Returns the url with all credentials removed (best effort)
+ Returns the url with all credentials removed
"""
- if not url.startswith('http://') and not url.startswith('https://'):
+ try:
+ parsed = urlparse(url)
+ except ValueError:
return url
- parsed = urlparse(url)
- if parsed.username and parsed.password:
- url = url.replace(f'{parsed.username}:{parsed.password}@', '')
- return url
+ netloc = parsed.hostname or ''
+ if parsed.port:
+ netloc += f':{parsed.port}'
+ safe_url = (parsed.scheme, netloc, parsed.path,
+ parsed.params, parsed.query, parsed.fragment)
+ return urlunparse(safe_url)

@staticmethod
def _get_filetype(f: Path):
--
2.53.0

Felix Moessbauer

unread,
Apr 29, 2026, 3:18:23 AM (11 days ago) Apr 29
to kas-...@googlegroups.com, jan.k...@siemens.com, Felix Moessbauer, Keyvan Hardani
Proposed-by: Keyvan Hardani <keyvan....@ieee.org>
Signed-off-by: Felix Moessbauer <felix.mo...@siemens.com>
---
tests/test_attestation.py | 53 +++++++++++++++++++++++++++++++++++++++
1 file changed, 53 insertions(+)
create mode 100644 tests/test_attestation.py

diff --git a/tests/test_attestation.py b/tests/test_attestation.py
new file mode 100644
index 000000000..f82985717
--- /dev/null
+++ b/tests/test_attestation.py
@@ -0,0 +1,53 @@
+# kas - setup tool for bitbake based projects
+#
+# Copyright (c) Siemens AG, 2026
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be
+# included in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+# SOFTWARE.
+
+import pytest
+from kas.attestation import Provenance
+
+
+...@pytest.mark.parametrize('url,expected', [
+ # plain https
+ ('https://example.com/siemens/kas.git',
+ 'https://example.com/siemens/kas.git'),
+ # https with user:password
+ ('https://user:pass...@example.com/siemens/kas.git',
+ 'https://example.com/siemens/kas.git'),
+ # https with user only
+ ('https://us...@example.com/siemens/kas.git',
+ 'https://example.com/siemens/kas.git'),
+ # https with port and credentials
+ ('https://user:pass...@example.com:8443/siemens/kas.git',
+ 'https://example.com:8443/siemens/kas.git'),
+ # http with credentials
+ ('http://token:x-oaut...@example.com/repo.git',
+ 'http://example.com/repo.git'),
+ # ssh without credentials
+ ('ssh://g...@example.com/siemens/kas.git',
+ 'ssh://example.com/siemens/kas.git'),
+ # plain URL without credentials
+ ('https://example.com/path?query=1#frag',
+ 'https://example.com/path?query=1#frag'),
+ # empty string
+ ('', ''),
+])
+def test_strip_credentials(url, expected):
+ assert Provenance._strip_credentials(url) == expected
--
2.53.0

Jan Kiszka

unread,
Apr 29, 2026, 4:38:21 AM (11 days ago) Apr 29
to Felix Moessbauer, kas-...@googlegroups.com, Keyvan Hardani
On 29.04.26 09:18, 'Felix Moessbauer' via kas-devel wrote:
> When using a credential that just consists of a username (commonly used
> for tokens), we currently do not strip it as the code only handles the
> username:password case correctly. By that, token might be leaked into
> the attestation data.
>
> We fix this by manually reconstructing the URL that is added to the
> attestation data and leave out the credential part.
>

I've added here

"Note that this leak is actually only possible when the user best
best practices of credential handling as also documented in kas."

to clarify that this is note a serious leak of kas itself.
Thanks, both applied.

Jan

--
Siemens AG, Foundational Technologies
Linux Expert Center
Reply all
Reply to author
Forward
0 new messages