WARDEN-WP-0036: tighten attended-login stdout/stderr allowlist
Reject non-null wrap_info (a wrapping token survives token revoke -self), non-empty data, empty client_token, and leading whitespace before the OIDC stderr prompt. Fail-closed and hand-off tests now run through the CLI and assert sentinel absence from both audit files. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Assistant: claude-code Assistant-Model: opus Assistant-Process: 680842@bnt-lap001 Assistant-Session: 54eb9e8e-7d6b-4f0c-b7a6-a6db62075883
This commit is contained in:
parent
8a426fba69
commit
6e1430073c
3 changed files with 90 additions and 21 deletions
|
|
@ -49,7 +49,9 @@ _TOKEN_HELPER_NAME = ".vault-token"
|
|||
# values are never logged, returned, stored, or included in an exception.
|
||||
#
|
||||
# stdout: empty, or exactly one JSON object shaped like a ``bao login -format=json``
|
||||
# response (api.Secret with an ``auth`` block).
|
||||
# response (api.Secret with an ``auth`` block). ``wrap_info`` must be null or
|
||||
# absent (a wrapping token would survive ``token revoke -self``), ``data`` null,
|
||||
# absent or empty, and ``auth.client_token`` a non-empty string.
|
||||
_LOGIN_JSON_TOP_TYPES: dict = {
|
||||
"request_id": (str,),
|
||||
"lease_id": (str,),
|
||||
|
|
@ -57,7 +59,7 @@ _LOGIN_JSON_TOP_TYPES: dict = {
|
|||
"renewable": (bool,),
|
||||
"data": (dict, type(None)),
|
||||
"warnings": (list, type(None)),
|
||||
"wrap_info": (dict, type(None)),
|
||||
"wrap_info": (type(None),),
|
||||
"mount_type": (str,),
|
||||
"auth": (dict,),
|
||||
}
|
||||
|
|
@ -78,7 +80,7 @@ _LOGIN_JSON_AUTH_TYPES: dict = {
|
|||
# stderr: empty, or exactly the OpenBao OIDC CLI prompt (browser-launch or
|
||||
# open-link variant, one https URL, optional wait line). Any other byte fails closed.
|
||||
_LOGIN_OIDC_STDERR = re.compile(
|
||||
r"\s*Complete the login via your OIDC provider\. "
|
||||
r"Complete the login via your OIDC provider\. "
|
||||
r"(?:Launching browser to:|Open the following link in your browser:)"
|
||||
r"[ \t]*\n\s*https://[^\s]+[ \t]*\n"
|
||||
r"\s*(?:Waiting for OIDC authentication to complete\.\.\.[ \t]*\n?\s*)?"
|
||||
|
|
@ -428,8 +430,13 @@ def _login_stdout_allowed(raw: bytes) -> bool:
|
|||
return False
|
||||
if not _typed_keys_allowed(parsed, _LOGIN_JSON_TOP_TYPES):
|
||||
return False
|
||||
if parsed.get("data"):
|
||||
return False
|
||||
auth = parsed["auth"]
|
||||
return "client_token" in auth and _typed_keys_allowed(auth, _LOGIN_JSON_AUTH_TYPES)
|
||||
if not _typed_keys_allowed(auth, _LOGIN_JSON_AUTH_TYPES):
|
||||
return False
|
||||
token = auth.get("client_token")
|
||||
return isinstance(token, str) and token != ""
|
||||
|
||||
|
||||
def _login_stderr_allowed(raw: bytes) -> bool:
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue