Encoding Chain Analyzer

Decode nested encodings automatically. Detects Base64, URL encoding and hex through multiple layers and shows every decoding step. Free, in-browser.

Advertisement

Unwind layered encodings until the payload is readable

You have a blob. It came out of a PowerShell command line, a phishing URL, a webshell, a config file, a CTF prompt, or a WAF log, and it is obviously encoded — but decoding it once produces another blob. That is the normal case, not the exception, and doing it by hand means guessing the format, pasting into a decoder, looking at the result, guessing again.

This tool does that loop for you. Paste the blob, press Analyze, and it repeatedly identifies the outermost encoding and strips it, showing every step: which encoding it detected, what went in, what came out, until nothing recognisable is left. The final row is the plaintext. Everything runs in your browser tab — the decoding functions are the browser's own atob, decodeURIComponent and TextDecoder, called from JavaScript in the page. Nothing is sent to a server, which is what makes it safe to paste a real captured payload.

Why attackers chain encodings

A single layer of Base64 is invisible to a human and completely visible to a scanner. Every layer added past the first is aimed at something specific:

  • Defeating signature matching. A detection rule looking for powershell -enc or a known C2 domain matches the plaintext, and it matches the single-Base64 form once someone writes that rule too. Wrapping the Base64 in URL-encoding produces a byte sequence nobody wrote a rule for.
  • Surviving transport. Some layers are not evasion at all. A payload that must ride inside a URL query string gets URL-encoded because it has to; if it then passes through a system that encodes it again, you get double-encoding as an artefact rather than a tactic.
  • Exploiting inconsistent decoding. Classic WAF bypasses rely on the filter decoding a different number of times than the application does. Double URL-encoding — %2557 decoding to %57 decoding to W — is the canonical example.
  • Buying time. Each layer costs an analyst a decision. Five layers of trivially reversible encoding is not cryptography, but it is friction, and friction is often all the payload needs.

None of this is encryption. Encoding is reversible by anyone with the format; it hides meaning from casual inspection and from naive pattern matching, not from analysis.

Recognising each layer by sight

The tool detects automatically, but knowing the signatures is what lets you tell a correct decode from a plausible-looking wrong one.

EncodingAlphabetGiveaways
Base64A–Z a–z 0–9 + / with = paddingLength is a multiple of 4; mixed case; one or two trailing =; text that looks like words with no spaces. Base64 of ASCII text often starts with recognisable prefixes — aHR0c is almost always http
Hexadecimal0–9 a–f onlyEven length; no letters past f; often space- or colon-separated in packet dumps. ASCII text in hex is full of 6 and 7 leading nibbles
URL / percent% followed by two hex digits%20 for space, %2F for slash, %3A for colon. A %25 is an encoded percent sign, which is your tell that a second layer of URL-encoding is present
ROT13Letters only, structure preservedWord lengths, spaces and punctuation look like English but the letters are wrong; gur is the, naq is and

How the detection loop works

On each pass the tool tests the current string in a fixed order — Base64, then hexadecimal, then URL-encoding, then ROT13 — and the first test that passes wins. It decodes, records the step, and starts again on the result. The loop stops when no test passes or when it reaches the maximum depth, which defaults to 10 and can be set anywhere from 1 to 20. Setting a shallow depth is genuinely useful when you want to inspect an intermediate layer rather than run all the way to the bottom.

The tests are conservative on purpose, because a decoder that accepts anything produces mojibake and calls it an answer:

  • Base64 requires at least four characters, the standard alphabet only, a length that is an exact multiple of four, and a decode result that contains no control characters.
  • Hex requires an even number of hex digits after whitespace is stripped, and a decode result with no control characters.
  • URL requires at least one %XX sequence and a decode result that differs from the input.
  • ROT13 requires the string to be letters, spaces and basic punctuation only, and the rotated result to contain at least two of a small set of common English words. This is what stops every English sentence from being "decoded" into gibberish.

A worked example

The built-in sample is VTJWamNtVjBJSEJoZVd4dllXUWxNakJrWldOdlpHVmtJUT09. Running it produces three steps:

StepDetectedResult
1Base64U2VjcmV0IHBheWxvYWQlMjBkZWNvZGVkIQ==
2Base64Secret payload%20decoded!
3URL encodingSecret payload decoded!

Step 2 is the instructive one. The output already looks like English, and a careless analyst stops there — but %20 is a live URL-encoded space, so there is one more layer. The loop keeps going precisely because "looks readable" is not the stopping condition; "no further encoding detected" is.

The double-URL case behaves the same way: paste %2557 and you get two steps, %2557%57W. If you only decode once you conclude the input was the literal text %57, which is exactly the confusion the technique is built on.

Failure modes to expect

Two of these are common enough that you should recognise them before they mislead you.

Unpadded Base64 is not detected. The length-multiple-of-four rule means SGVsbG8gV29ybGQ — fifteen characters, "Hello World" with the padding stripped — produces no steps at all. Many real-world emitters drop padding, and URL-safe Base64 (which substitutes - and _ for + and /) fails the alphabet test outright. The fix is manual: restore = padding to the next multiple of four, and translate - to + and _ to /, then paste again. Similarly, Base64 broken across lines with embedded whitespace or newlines will not be recognised — join it into one line first.

Some hex is misread as Base64. Hex digits are all inside the Base64 alphabet, so a hex string whose length happens to be a multiple of four passes the Base64 test, and Base64 is tried first. 646f776e6c6f61642e657865 is 24 characters of hex meaning download.exe, but the tool reports it as Base64 and returns high-byte noise. Drop one byte — 646f776e6c6f61642e6578, 22 characters — and the Base64 test fails on length, hex wins, and you get download.ex. Two workarounds: insert spaces between hex bytes if the length is awkward, or read the step label and distrust any Base64 step whose input was pure [0-9a-f] and whose output is unreadable. Where you are unsure what a hex string even is, the cipher identifier is the better first stop.

Other limits are simply scope. The tool handles four encodings and no others. It will not touch:

  • Base32, Base58, Base85/Ascii85, or quoted-printable
  • gzip, zlib or deflate — a H4sI Base64 prefix means the layer under it is gzip, and you will need a different tool
  • HTML entities (A), JavaScript unicode escapes (\u0041), or PowerShell UTF-16LE Base64, whose decode looks like text with a null byte between every character
  • XOR, RC4 or any keyed transformation — these are encryption, not encoding, and cannot be reversed without the key
  • Character-code arrays such as [72,101,108,108,111] or chr() concatenations

When the chain stops at something that clearly is not plaintext, that residue is the interesting part: it usually means the innermost layer is one of the above. Compressed data, encrypted data and UTF-16 text all look different from each other and from random bytes, and identifying which you are holding is the next step.

Where these chains show up

PowerShell command lines. The -EncodedCommand parameter takes Base64 of UTF-16LE, so the first decode gives you text with a null byte between every character. This tool will report the Base64 step, and the output will look like spaced-out letters — that is the expected appearance of UTF-16, not a failure. Strip the nulls and the script is readable.

Phishing URLs. Redirect chains commonly carry the real destination as a Base64 parameter, which is itself URL-encoded because it is riding in a query string. Paste the parameter value alone, not the whole URL, or the surrounding path characters will fail the alphabet tests.

Webshells and dropper scripts. Layered base64_decode and urldecode calls wrapped around an eval are the standard shape. Reading the nesting order in the source tells you the decode order to expect, and the step list here should match it in reverse.

Log analysis and WAF tuning. When a request was blocked and you need to know what it actually asked for, the request line is usually percent-encoded at least once. Double-encoding in a blocked request is itself a finding — legitimate clients rarely encode twice.

CTF challenges. Deliberately deep chains are a genre. Raising the depth limit to 20 and reading the step list is faster than manual iteration, and where the chain stops on something the tool does not handle, the label on the last successful step usually names the family you are dealing with.

Practical notes

  • Every step is copyable. Grab an intermediate value if you want to work on one layer in isolation.
  • The final result deep-links onward. Buttons carry the decoded output into the Base64 encoder and decoder, the XOR cipher tool, or the cipher identifier, so you do not re-paste by hand.
  • The tool accepts a ?text= URL parameter, which pre-fills the input — handy for bookmarking a case or passing one to a colleague. Remember that anything in a URL is visible in browser history and any proxy log, so do not do this with a payload that is itself sensitive.
  • The confidence numbers shown next to each step are fixed labels per encoding type, not a computed probability. Judge a step by whether its output makes sense, not by the badge.
  • Decoding is not detonation. Nothing here executes what it decodes — the output is inert text on the page. Handle the result with the same care you would give any extracted payload once it leaves the tab.
This tool is provided for informational and educational purposes only. All processing happens in your browser — no data is sent to or stored on our servers. While we strive for accuracy, we make no warranties about the completeness or reliability of results.