⚠ Thin coverage — only 14 disclosed reports for this class; illustrative, not exhaustive.
# Grep any reachable log for the classic secret sinks
grep -RniE 'authorization|bearer|access_token|refresh_token|api[_-]?key|password|ldap_bind' /path/to/logs
# Argument-dump loggers: serialized call args that hold secrets
grep -RniE 'validateUserPass|areCredentialsValid|ldap_bind|addUser|toCurl' /path/to/logs
# PII / raw statements baked into error logs
grep -RniE 'INSERT INTO|UPDATE .* SET|VALUES \(' /path/to/logs
Find which of these the target exhibits, then apply the matching probe.
The single most common sink. A generic handler serializes the arguments of the failing call — and the secret was passed as one of those arguments. Trigger the failure path to make it fire.
# Fail auth against a 2FA-required account -> the auth exception logs the raw password arg
curl -u 'VICTIM:REALPASSWORD' https://TARGET/remote.php/dav/
# Resulting log line:
# OCA\DAV\Connector\Sabre\Auth->validateUserPass('VICTIM', 'REALPASSWORD')
# Make the LDAP/auth backend unreachable so the failing bind() logs its DN + password,
# or drop log level to debug so a blanket arg-dumper serializes ldap_bind:
grep -i ldap_bind /path/to/nextcloud.log
# Calling LDAP function ldap_bind with parameters [{},"uid=VICTIM","REALPASSWORD"]
# Raise component verbosity so the curl-command dumper serializes the bearer token
# (klog.V(9) round_trippers.go toCurl(); debug-level app request dumpers):
kubectl -n kube-system logs <controller-manager-pod> | grep -iE 'Authorization|curl -k'
# curl -k -v -XGET -H "Authorization: Bearer <TOKEN>" 'https://TARGET' <- replay this token
# Integration/bot exhaust leaks live OAuth tokens after any auth flow:
grep -RniE 'access_token|refresh_token|Authorization' /var/log/hubot* /path/to/integration-logs
On DB failure, an error handler writes the entire failed statement — with every field value — into a log file. Find a reachable log, then grep for statements, not just stack traces.
# Locate an exposed/guessable error log, then pull the embedded PII out of raw INSERTs
grep -RniE 'INSERT INTO|UPDATE .* SET' /path/to/logs
# INSERT INTO dli.dli_customer_data VALUES (seq.NEXTVAL, SYSDATE, <name>, <email>, <phone>, <address>, ...)
Any request-controlled value written into a space/quote-delimited log without escaping lets you forge lines, drop entries, or inject terminal escapes. The fields defenders forget: $remote_user (Basic-auth username), REQUEST_METHOD, path, and User-Agent.
# Delimiter smuggling: a space in the decoded Basic-auth username adds a column,
# breaking the space-delimited log parser so the whole entry is silently dropped.
curl -X POST -u '- A:B' 'https://TARGET/graphql?secret=1'
# Authorization: Basic LSBBOkI= -> $remote_user = '- A' -> extra field -> ingestion drops the line
The same class, delivered as raw control bytes. Send 0x08 (backspace) / 0x1b (ESC) inside a field the logger prints verbatim, and the sequence executes when an operator tails the log in a terminal.
GET\b\b\bPOST /sign_in?x=1 HTTP/1.0
Host: TARGET
# \b = 0x08 backspace, ESC = 0x1b -> hide/forge lines, move cursor, set the terminal title
# (the logger escaped the query string but printed REQUEST_METHOD raw)
Two distinct failures. Spoof the recorded identity by poisoning a trusted-but-forgeable field; or evade by routing the call through an endpoint wired to a different (or no) logging path.
POST /accounts/login/ HTTP/1.1
Host: TARGET
X-Forwarded-For: VICTIM-IP
Content-Type: application/x-www-form-urlencoded
username=victim&password=x
# App trusts raw XFF (no trusted-proxy allowlist) -> forged IP lands in the profile audit + admin console
# Silent enumeration: baseline hits CloudTrail, the alternate endpoint does not.
aws s3tables list-table-buckets --region us-west-2 # baseline -> event appears
aws s3tables list-table-buckets --region us-west-2 \
--endpoint-url https://s3tables.us-west-2.<internal>.people.aws.dev \
--no-verify-ssl # NO CloudTrail event = blind spot
# permitted principal -> {"tableBuckets": []}
# denied principal -> AccessDeniedException: not authorized to perform: s3tables:ListTableBuckets
Logging bugs are almost never the endpoint — they feed the next stage.
The techniques above are the general method. Below, each disclosed HackerOne report is a catalogued example — concrete payload, outcome, and matching practice lab. 14 in this class.
Real-world example
Plaintext password of failed login written to application log
◆ High
Specimen #244092 · nextcloud · none · 9 votes · resolved
Program nextcloudSurface webChain log credential leak -> credential reuse against LDAP/othe
Root cause
When a WebDAV/2FA login failed, the Sabre Auth code path threw and logged the exception with the method arguments, writing the user's (correct) plaintext password into the application log where admins/debuggers could read it.
Method
- Trigger a failing auth path that still receives the real password (e.g. WebDAV basic auth against a 2FA-required account)
- Inspect the application/exception log for the logged call arguments
- Read the plaintext credential from the stack trace: Auth->validateUserPass('user','PASSWORD')
# log line pattern
OCA\DAV\Connector\Sabre\Auth->validateUserPass('USER', 'THE_PASSWORD')
Insight — Exception handlers that log function arguments will spill secrets passed as parameters (passwords, tokens, card numbers). Look for verbose debug/exception logs and endpoints that fail after receiving credentials; the log becomes a credential store reusable against LDAP/other services.
Real-world example
Error log records full SQL INSERT statements containing PII
◆ High
Specimen #3242830 · deptofdefense · none · 7 votes · resolved
Program deptofdefenseSurface web
Root cause
On DB failure the app's error handler writes the entire failed SQL INSERT (including all customer field values) into a log file that is itself reachable/retrievable, persisting cleartext PII well beyond intent.
Method
- Locate exposed/retrievable log files (ORDER_ERROR_LOG, error.log, debug logs) via path guessing or listing
- Search the log for full INSERT/UPDATE statements
- Extract the embedded PII (names, emails, phones, addresses, customer/transaction data)
# ORDER_ERROR_LOG contains:
INSERT INTO dli.dli_customer_data VALUES ( dli_customer_data_sequence.NEXTVAL, SYSDATE, <full_name>, <email>, <phone>, <address>, ... )
# hunt:
grep -RniE 'INSERT INTO|UPDATE .* SET' /path/to/logs
Insight — Two-part lesson: (1) as an app antipattern, logging raw failed SQL statements bakes PII into logs; (2) as a hunter, when you find any reachable log/debug file, grep it for INSERT/UPDATE statements and connection strings, not just stack traces.
Real-world example
Silent AWS IAM permission enumeration via non-production endpoints that skip CloudTrail
◆ Medium
Specimen #3780277 · aws_vdp · none · 64 votes · resolved
Program aws_vdpSurface cloudChain Stolen creds -> silent permission enumeration here -> Tag cloud-aws
Root cause
AWS spins up non-production/personal service endpoints (test NLBs, *.people.aws.dev, employee-aliased hosts) that accept real signed SigV4 requests with standard IAM credentials and perform normal IAM authorization, but do NOT emit a matching CloudTrail event. An attacker who redirects the AWS CLI/SDK to one of these hosts can test whether stolen credentials hold a given permission without generating the failed/successful API log that detection relies on.
Method
- Obtain/target a set of AWS credentials (the attacker case: stolen access keys or an assumed role).
- Discover candidate non-production endpoints: monitor Certificate Transparency logs (crt.sh / cert-stream) for hostnames like <service>*.people.aws.dev, s3table-nlb-personal-*.elb.<region>.amazonaws.com, <service>-fips.*, and other employee/test-named service hosts.
- Baseline: run a normal read call against the production endpoint (e.g. `aws s3tables list-table-buckets`), wait 10-15 min, confirm a CloudTrail event appears.
- Redirect the same call to a candidate endpoint with `--endpoint-url` (add `--no-verify-ssl` / short timeouts as needed) and repeat with both a privileged and an unprivileged principal.
- Diff the two responses: a permitted principal returns normal data / a non-IAM error, a denied principal returns an explicit AccessDeniedException naming the action. That differential leaks whether the credential holds the permission.
- Re-check CloudTrail (all regions) and confirm NO matching event was produced for either principal -> the enumeration was invisible.
# Baseline (production, DOES log to CloudTrail):
aws s3tables list-table-buckets --region us-west-2
# Silent test against a non-production endpoint (NO CloudTrail event):
aws s3tables list-table-buckets --region us-west-2 \
--cli-connect-timeout 10 --cli-read-timeout 10 \
--endpoint-url https://s3tables.us-west-2.<internal>.people.aws.dev \
--no-verify-ssl
# Response differential reveals the permission bit:
# permitted principal -> {"tableBuckets": []}
# denied principal -> AccessDeniedException: ... not authorized to perform: s3tables:ListTableBuckets
Insight — Detection of credential abuse in AWS assumes every API call hits CloudTrail. Any alternate host that speaks the same API but is not wired into CloudTrail is a logging blind spot. When assessing a cloud provider or a large SaaS, hunt for non-production/mirror endpoints (Certificate Transparency is the cheap discovery channel) and test whether they are (a) reachable with prod credentials and (b) absent from the audit log. The `--endpoint-url` override is the general trick: same signed request, different host, different (or zero) logging.
Real-world example
Secrets logged in cleartext (API keys and passwords in logs)
◆ Medium
Specimen #1662194 · Omise · awarded · 31 votes · resolved
Program OmiseSurface other
Root cause
Sensitive values were written to logs in cleartext: the Omise client debug-logs the Authorization/secret API key, and (merged 469668) Nextcloud's exception serializer logs full method parameters including user passwords when an exception is thrown.
Method
- Enable/inspect debug logging or trigger an exception in a code path handling secrets
- For Omise: run any request with logging level DEBUG; secret key appears via logger.debug('Authorization: %s', api_key)
- For Nextcloud (469668): create a user while SMTP is down; the addUser exception stack trace logs the password parameter
- Read the secrets from the log output
# Omise omise/request.py L88/L111
logger.debug('Authorization: %s', self.api_key)
# Nextcloud exception log (SMTP failure during addUser)
addUser("[user]", "[PASSWORD]", ...) at Dispatcher.php:166
Insight — Grep the codebase/logs for logger.debug/print of api_key, Authorization, password, token. Exception serializers that dump call arguments are a stealthy sink: filter by parameter name ($password), not by an allowlist of methods, or passwords leak on every unexpected error.
Real-world example
CloudTrail attribution obfuscation: FIPS endpoints log attacker IP/user-agent as 'AWS Internal'
◆ Medium
Specimen #2979238 · aws_vdp · none · 29 votes · resolved
Program aws_vdpSurface cloudTag cloud-aws
Root cause
For certain AWS service endpoints (observed on FIPS endpoints across several services), CloudTrail still records the event but populates the sourceIPAddress and userAgent fields with the literal string 'AWS Internal' instead of the caller's real IP and client. An attacker routing calls through these endpoints keeps the action logged but strips the network/host indicators an investigator would pivot on.
Method
- Baseline: run a call against the normal production endpoint (e.g. `aws comprehendmedical list-phi-detection-jobs`), wait 5-10 min, inspect the CloudTrail record and confirm sourceIPAddress and userAgent are populated with the real values.
- Repeat the identical call against a FIPS endpoint via `--endpoint-url` (e.g. comprehendmedical-fips.us-east-1.api.aws).
- Inspect the resulting CloudTrail event: sourceIPAddress and userAgent now read 'AWS Internal', hiding the attacker's IP and client fingerprint.
- Prefer these endpoints for logged-but-attributed operations to degrade incident-response pivoting on network indicators.
# Baseline (real IP + user-agent land in CloudTrail):
aws comprehendmedical list-phi-detection-jobs
# Via FIPS endpoint -> CloudTrail records sourceIPAddress/userAgent = "AWS Internal":
aws comprehendmedical list-phi-detection-jobs \
--endpoint-url https://comprehendmedical-fips.us-east-1.api.aws
Insight — Logging is not binary. An event can be present in the audit log yet still be useless for attribution if the identifying fields are blanked or spoofed. When reviewing any audit pipeline, don't just check whether an action is logged -- check whether the WHO/WHERE (source IP, user-agent, principal) survive. Alternate endpoint families (FIPS, dualstack, regional mirrors) can be logged by a different code path that fills these fields differently.
Real-world example
Credentials written to application debug logs
◆ Medium
Specimen #2101165 · nextcloud · awarded · 28 votes · resolved
Program nextcloudSurface web
Root cause
A generic pre-call logger json_encodes all arguments of every LDAP function at debug level, so ldap_bind's password argument lands in cleartext in the log file (CVE-2023-48305).
Method
- Set loglevel to 0 (debug) on an LDAP-backed instance
- Log in as an LDAP user
- Grep the log for 'ldap_bind' and read the cleartext password in the message args
grep ldap_bind nextcloud.log
# message: Calling LDAP function ldap_bind with parameters [{},"uid=<USER>","<PASSWORD>"]
Insight — Blanket 'log all function args' wrappers are a recurring credential-leak sink. When you have log read access (local admin, log-viewer app, exposed log endpoint), grep for bind/login/auth function names; secrets often sit in serialized argument arrays.
Real-world example
Log injection / entry-drop via Basic-auth username in nginx $remote_user
◆ Medium
Specimen #447488 · security · none · 19 votes · resolved
Program securitySurface web
Root cause
nginx logs $remote_user (decoded from Authorization: Basic) unquoted and unescaped between space-delimited fields. An attacker embeds a space/delimiter in the username, adding an extra column that breaks downstream log ingestion so the entry is silently discarded.
Method
- Send Basic auth whose decoded username contains a whitespace/delimiter
- Request is proxied normally but the access-log line gains an extra field
- Log pipeline fails to parse and drops the entry -> request is unlogged (anti-forensics)
curl -X POST -u '- A:B' 'https://TARGET/graphql?secret=1'
# Authorization: Basic LSBBOkI= -> $remote_user = '- A' -> extra column in space-delimited access log
Insight — Attacker-controlled fields written into space/quote-delimited logs without escaping enable log forging and, worse, log-drop that hides malicious requests from the SIEM. Audit every request-controlled value ($remote_user, cookies, UA) in log_format for unquoted placeholders.
Real-world example
High log verbosity prints Kubernetes Secret contents in cloud controller logs
◆ Medium
Specimen #966383 · kubernetes · awarded · 3 votes · resolved
Program kubernetesSurface cloudChain pods/log read in kube-system -> Secret contents in controTag cloud
Root cause
The vSphere legacy cloud provider registers a Secret informer and logs the full secret object; with kube-controller-manager log verbosity set to 4 or higher, secret data (passwords, private keys, service-account tokens) is written to the controller-manager log on every secret create/update (CVE-2020-8563).
Method
- Confirm the cluster runs vSphere as cloud provider with controller-manager verbosity >= 4.
- As a principal that can read kube-system pod logs (GET pods/log), tail the cloud-controller-manager / kube-controller-manager pod log.
- Trigger or wait for a Secret create/update; read the secret payload printed by the SetInformers handler.
- If a leaked value is a service-account token, use it to escalate privileges.
kubectl -n kube-system logs <kube-controller-manager-pod> | grep -i secret
# with --v=4+, secret objects (data incl. tokens/keys) are printed on create/update
Insight — Verbose logging is a first-class secret sink in cloud/orchestration platforms. Whoever can read component logs (pods/log in kube-system, node journald, log aggregators) effectively reads secrets. Audit log verbosity flags and which identities can read the logs; a leaked SA token is a direct privesc.
Real-world example
ANSI/terminal escape-sequence injection into request logs
◆ Medium
Specimen #1411867 · rails · none · 2 votes · resolved
Program railsSurface web
Root cause
Rack CommonLogger writes the raw REQUEST_METHOD (and other request metadata) to the log without stripping control characters, so control bytes/escape sequences land verbatim in log files.
Method
- Send a request whose method or path contains raw control bytes (backspace 0x08, ESC 0x1b).
- The logger escapes the query string but prints the request method as-is.
- When an operator views the log in a terminal, the injected escape sequences execute (cursor moves, color, title-set, potential command hiding).
GET\b\b\bPOST /sign_in?test1=1\b2 HTTP/1.0
Host: 127.0.0.1:4567
# \b = 0x08 backspace; ESC (0x1b) sequences enable ANSI injection / log forging
Insight — Anywhere raw request fields (method, UA, path, headers) are echoed to logs, test control-char/ANSI injection: hide entries with backspaces, forge lines with CRLF, or trigger terminal escape sequences on whoever tails the log. Same class curl fixed in WEBrick years earlier.
Real-world example
Bearer tokens logged via klog verbose toCurl() (CVE-2019-11250)
◆ Medium
Specimen #952771 · kubernetes · awarded · 1 votes · resolved
Program kubernetesSurface otherChain Token in logs -> log-reader (Eve) replays bearer token -&Tag jwt
Root cause
client-go's debuggingRoundTripper masks header values only in the debugRequestHeaders branch; the preceding debugCurlCommand branch calls reqInfo.toCurl(), which serializes all request headers (including Authorization) unmasked into logs at high klog verbosity.
Method
- Run kube components at high verbosity (klog.V(9)/debugCurlCommand)
- Observe round_trippers.go logging a full 'curl -k -v -H "Authorization: <token>" URL' line
- Anyone with log access replays the bearer token to impersonate the user
// round_trippers.go toCurl(): builds "curl -k -v -X%s %s '%s'" with raw -H "Authorization: <bearer>"
// maskValue() applied only in debugRequestHeaders branch, not in toCurl()
Insight — Credential masking must cover every logging code path, not just one. When auditing verbose/debug logging, grep for curl-command builders, request dumpers, and toString()/toCurl() helpers that serialize headers without reusing the masking routine - Authorization/Cookie/token headers leak to log readers who lack cluster access.
Real-world example
OAuth tokens written to integration logs in cleartext
◆ Medium
Specimen #1394399 · rocket_chat · none · 1 votes · resolved
Program rocket_chatSurface webTag oauth
Root cause
An integration/bot subsystem (Hubot) logs full request/response data including OAuth access tokens in plaintext, so anyone with log access (ops, log aggregation, shared containers) can lift live credentials.
Method
- After any OAuth/token flow, inspect application, integration, and bot logs (Hubot, webhook handlers, debug logs) for Authorization headers, access_token, refresh_token, or bearer values.
- Confirm the tokens are live (unredacted) and grant access to the linked system; report as cleartext storage of secrets.
Insight — Secrets leak most often not in the app UI but in its exhaust: integration/bot logs, debug output, and log shippers. Always grep captured logs and any log-viewing UI for token/bearer/authorization/password after exercising auth flows. Fix is to redact/placeholder tokens before logging.
Real-world example
Secret logged before validation/deletion (kubeadm bootstrap token)
◆ Low
Specimen #972561 · kubernetes · awarded · 7 votes · resolved
Program kubernetesSurface other
Root cause
CLI logs the raw input (which may be a full bootstrap token, not just an ID) at verbosity before parsing/deleting it; if deletion fails the token stays valid and is now persisted in logs.
Method
- Locate log calls that print user/CLI input prior to type/validity checks
- Note where input may be a full credential vs an identifier
- Confirm the credential remains valid on the error path -> log-readable secret
// kubeadm cmd/token.go RunDeleteTokens
klog.V(1).Infof("[token] parsing token %q", tokenIDOrToken) // logs full token before it is parsed
Insight — Grep source/logs for the pattern 'log the raw argument, then decide if it's a secret'. Sensitive material logged before validation (or on failure paths) is a durable credential leak to anyone with log access.
Real-world example
Credentials written to logs on error path (missing from sensitive-param sanitize list)
◆ Low
Specimen #264426 · nextcloud · none · 2 votes · resolved
Program nextcloudSurface webChain backend error -> creds in logs -> (with log-read/LFI)
Root cause
When an LDAP backend is unavailable, the failing method call (bind/areCredentialsValid/etc.) is logged with its arguments; those methods were not enumerated in the log's sensitive-parameter exclusion list, so plaintext usernames and passwords land in log files.
Method
- Trigger the auth backend error path (e.g. make the LDAP server unreachable)
- Observe that the failing method call is logged with full arguments
- Read plaintext credentials from the application log
# lib/private/Log.php $methodsWithSensitiveParameters missing:
# bind, areCredentialsValid, invokeLDAPMethod, checkPasswordNoLogging
# -> LDAP bind() DN + password logged in cleartext on connection failure
Insight — Audit error/exception logging paths: happy-path logging is usually sanitized, but failure handlers frequently dump full method args including passwords/tokens. When reviewing source, grep the log-scrubbing allowlist and diff it against every method that receives a secret. As an attacker, force auth/backend errors and then find a log-read primitive to harvest creds.
Real-world example
Audit-log source-IP spoofing via X-Forwarded-For at login
◆ Info
Specimen #296632 · weblate · none · 4 votes · resolved
Program weblateSurface webTag logging
Root cause
The application (Dockerized Weblate behind a reverse proxy) trusts the client-supplied X-Forwarded-For header as the real client IP and writes it directly into audit-log entries without validating it against the actual trusted-proxy chain.
Method
- Locate a feature that records the client IP into an audit/security log (login events, profile activity, admin console).
- Send the login (or logged action) with a spoofed X-Forwarded-For: ATTACKER-CHOSEN-IP header.
- Observe the forged IP appear in the user profile audit log and admin console.
- Optionally probe adjacent sinks: here User-Agent value '"<b>test was stored unencoded (no XSS, but a sign the field flows into other sinks).
POST /accounts/login/ HTTP/1.1
Host: TARGET
X-Forwarded-For: 1.2.3.4
Content-Type: application/x-www-form-urlencoded
username=victim&password=...
Insight — When an app sits behind a proxy, check whether logged/displayed client IPs come from X-Forwarded-For (or X-Real-IP) without a trusted-proxy allowlist. If so you can poison the audit trail, frame another IP, or hide the real source of a compromise. Also test whether the same forgeable IP feeds rate-limiting or IP-based access control for higher impact.