You are about to paste CloudWatch output, a Lambda log or an
aws --debug transcript into an issue, a chat or a model. Here is what in it is
actually a credential, which half a scanner can see, and what to do about the half it cannot.
Scrub it, then read the output yourself. The access key id — the
AKIA or ASIA string — is the easy half: fixed prefix, fixed
length, found by any scanner, and on its own it unlocks nothing. The 40-character
secret access key next to it has no prefix, no checksum and no distinctive shape, so it
is found by the name in front of it and by nothing else. If it is sitting bare on a line, a
pattern scanner — mine included — will not see it. That is the line you have to find
with your eyes.
If the credential was live, redaction is not the fix. Scrubbing your copy changes nothing about the log, and CloudWatch Logs has no API for deleting one event — the smallest thing you can delete is a log stream. Rotate the key first and read CloudTrail second; the clean paste only protects the next reader.
Access key ids, anything behind a name like aws_secret_access_key or
x-amz-security-token, and public IP addresses come back as numbered placeholders,
so the log is still readable enough to debug from. The detectors run in this page; there is no
upload, and no request is made with your text in it.
AKIA for a
long-term IAM user key, ASIA for a temporary one — then sixteen more of
A–Z and 0–9. No lowercase.
It is the username half. It names an identity; it proves nothing.
AWS prints it itself: it is in every CloudTrail record the key ever caused.
bare on a line, tool output[AWS_KEY_1] caught
+ and
/. No prefix, no checksum, no fixed anything — the same shape as a base64
hash, a build id or a chunk of a minified bundle.
It is the password half. Combined with the id, it signs requests as
that identity until someone deactivates it.
bare on a line, tool outputwJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY unchanged
behind its name, tool outputaws_secret_access_key = [SECRET_1] caught
The greppable half is the
harmless half. Every scanner in the world finds the AKIA string, and every
scanner — including this one — needs a name, a quote or an = next to the
secret to find that. So an AKIA in your log is not the finding. It is the signpost:
go and look at what is on the same line, in the same JSON object, in the next forty
characters.
Both values above are AWS’s own published documentation example pair, which is why they are safe to print here — and why a scanner that keeps a blocklist of famous example keys would tell you this figure is clean. Output shown is what the detectors on this page actually return for those inputs.
Verified by running each of these through the same detectors the box above uses. Where it misses, it says so — a redactor that overstates its reach is worse than none, because you stop reading the output.
Twenty characters, no name needed. AKIA is a long-term IAM user key;
ASIA is a temporary one from STS, which is what a Lambda function, an ECS task or
anyone who ran assume-role is using.
in AWS_ACCESS_KEY_ID=AKIAIOSFODNN7EXAMPLE out AWS_ACCESS_KEY_ID=[AWS_KEY_1]
The rule reads the name: aws_secret_access_key,
"SecretAccessKey":, secret_key=, anything ending in
_secret or access_key, in an assignment, a JSON field or a YAML block.
Alone on a line it is forty characters of base64 with nothing to distinguish it from a checksum,
and it comes back untouched.
in "SecretAccessKey": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY" out "SecretAccessKey": "[SECRET_1]" in wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY out wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY
The full Log Redactor has an opt-in detector for long high-entropy strings that does catch the bare form. It is off by default because it also redacts your git hashes, your content digests and half of any minified file — the false-positive corpus page is the argument for leaving it off until you know your input warrants it.
Temporary credentials come as a triple: an ASIA id, a secret, and a session token
that is hundreds of characters long and, in the current format, begins
IQoJb3JpZ2lu. It is caught behind aws_session_token,
"SessionToken": or the x-amz-security-token header, and missed when it
is dumped on its own.
in x-amz-security-token:IQoJb3JpZ2luX2VjEJr//////////wEaCXVzLWVhc3Qt out x-amz-security-token:[SECRET_1]
Length is its own hazard here. If the CloudWatch console or your terminal hard-wrapped the token across two lines, the match ends at the break: you get a tidy placeholder and the tail of the token in the clear underneath it, which looks handled. Un-wrap before you paste.
Authorization header signature not redactedA signed request trace — curl -v, an SDK debug log, an API Gateway access
log with headers on — carries a line like this. The key id inside Credential=
is replaced. The signature at the end is not, and neither is the credential scope
(date, region, service).
in Authorization: AWS4-HMAC-SHA256 Credential=AKIAIOSFODNN7EXAMPLE/20260902/us-east-1/s3/aws4_request, SignedHeaders=host;x-amz-date, Signature=fe5f80f77d5fa3beca038a248ff027d0445342fe2855ddc963176630326f1024 out Authorization: [SECRET_1] Credential=[AWS_KEY_1]/20260902/us-east-1/s3/aws4_request, SignedHeaders=host;x-amz-date, Signature=fe5f80f77d5fa3beca038a248ff027d0445342fe2855ddc963176630326f1024
Two things in that output are worth knowing. The first is cosmetic and mine: the assignment
rule sees the word Authorization followed by a colon and replaces the algorithm name
AWS4-HMAC-SHA256 as if it were a value. Harmless noise, but it is noise, and I would
rather you read it here than wonder.
The second is not cosmetic and is not mine. That signature is a keyed hash over one canonical request on one date. You cannot run the derivation backwards to recover the secret, and it will not sign anything else — so a leaked request signature is genuinely less bad than a leaked secret. Do not confuse that with the next case, where the signature is the credential.
This is the one to check by hand. A presigned URL is a complete, transferable authorisation:
anyone holding it can perform that operation, from any machine, with no key of their own, until
it expires — up to seven days for a URL signed with a long-term key, and only until the
session ends for one signed with temporary credentials. The tool replaces the key id in
X-Amz-Credential and leaves X-Amz-Signature alone.
in ...&X-Amz-Credential=ASIAY34FZKBOKMUTVV7A%2F20260902%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Expires=604800&X-Amz-Signature=fe5f80f7…326f1024 out ...&X-Amz-Credential=[AWS_KEY_1]%2F20260902%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Expires=604800&X-Amz-Signature=fe5f80f7…326f1024
(Query string abridged in the middle; the point is that the signature parameter is byte-for-byte
identical on both lines.) If your log prints presigned URLs — download links, upload
targets, anything your service handed a browser — treat the whole URL as a secret and
delete the line rather than redacting it. X-Amz-Expires tells you how long you have,
and it is not a reason to relax.
A 12-digit account id and the ARNs that embed it are identifying, not authenticating. They name your account, your roles, your buckets and often your project. Knowing them lets someone guess at role names or try a confused-deputy angle; it does not let them call anything. The tool leaves them, because redacting every ARN turns an AWS log into unreadable soup and you lose the ability to debug from your own paste.
If a bucket name, an internal hostname or a role name really is confidential in your organisation, that is what the custom terms box in the full Log Redactor is for. No regular expression can guess which of your nouns are secret.
AROA…, AIDA…, AGPA… and their
relatives share the twenty-character shape, so the detector replaces them too. They are
not secrets — they are stable unique ids for roles, users, groups and
policies, and they turn up in CloudTrail and in IAM policy conditions. Being wrong in this
direction costs you a placeholder in a log; being wrong in the other direction costs you a key.
The prefix field guide lists which is which.
in "AssumedRoleId": "AROAY34FZKBOKMUTVV7A:deploy-session" out "AssumedRoleId": "[AWS_KEY_2]:deploy-session"
Worth knowing, because the redactor treats the symptom and every one of these is fixable at the source.
The Lambda execution environment holds AWS_ACCESS_KEY_ID,
AWS_SECRET_ACCESS_KEY and AWS_SESSION_TOKEN for the function’s
role, injected by the service. Any exception handler that dumps the environment — a
“log everything and figure it out later” catch block, a debug print of a config
object built from process.env or os.environ — writes live
temporary credentials into CloudWatch, with the retention period you set years ago, for everyone
with logs:FilterLogEvents to read. This is the single most common way an AWS secret
reaches a log, and it is invisible until someone pastes the log somewhere.
aws --debug transcript pasted into a ticketDebug output prints the request headers, so a run using temporary credentials puts the whole
session token in your terminal, along with the Authorization line and the canonical
request. The AWS CLI does not print your secret access key as part of that trace — but the
transcript people share is usually a whole terminal capture, and the other things in that window
are an env, a cat of a credentials file, or a copied
export. Scrub the window, not the command.
If you only want to know which key is in play, aws configure list is the safe
question: it prints just the last four characters of each value.
A query result is the raw event text. Anything the shapes above describe is in
@message exactly as it was written, and the export button hands you a file of it.
Redact after you export and before you attach — and if the credential is really there,
exporting it is already the second copy.
X-Amz-Signature=, Signature=.ASIA credentials there is no key to delete — they expire on their
own, and if that is not soon enough, revoking the role’s active sessions denies everything
issued before this moment. Then read CloudTrail filtered on the access key id, which is the only
thing that tells you whether it was used.
The full order of operations after a leak is here.The box on this page and the tools below share one detector source, so you get the same answer in all three places — which matters when the log you cannot paste into a browser is the one you most need to scrub.
The full Log Redactor Every detector with a switch next to it, a custom terms box for your own bucket and host names, and the complete written account of what it misses. Same browser-only guarantee. The command-line version, for logs that never leave the host Pipe a file through it, keep a local key map so the placeholders are reversible, and run it in CI. No network, no telemetry, no dependencies.There is also npm install logscrub — the same detectors as a free, MIT-licensed
package with no dependencies, for scrubbing inside your own code before the log line is ever
written. That is the version that scales past a paste: a CloudWatch export, a whole log group, a
nightly job.
Detecting a secret in text you already have. If the question is whether a credential in a shared log was used, no redactor helps — that is CloudTrail, filtered on the access key id, and it is the step people skip because rotating feels like the end of the story.
Anything about GuardDuty findings, a compromised instance, or credentials taken from a running machine rather than read out of text. If an attacker had code execution, you do not know what they hold, and the response is a larger one than this page.
And it does not cover the general question of what else leaks out of a log — internal hostnames, customer email addresses, JWTs from your own auth, database URLs with the password in the middle. The two-minute check before you paste anything is the broader version of this page.