StegoToolkit

Document Steganography Extractor

Extract hidden payloads from DOCX, XLSX, PPTX and ODT documents. Reads the six formats this site's Hider writes. AES-256-GCM decryption, CTF flag detection and an anomaly score. Processed in your browser, not uploaded.

Auto-detect 6 methods
AES-256-GCM decrypt
Anomaly score
In-browser

Drop a document here or click to browse

DOCX · XLSX · PPTX · ODT · Max 200 MB

Processed in your browser

Your document is parsed and rewritten in this browser tab using JSZip and is not sent to a server. Usage statistics may record which options were used, never your document.

How to Decode a Steganographic Office Document (4 steps)

  1. Upload the DOCX, XLSX, PPTX or ODT file you suspect carries hidden data
  2. Quick mode runs Auto-Detect; Standard lets you pick one of the six methods; Forensic adds Reed-Solomon recovery, watermark attribution and analysis tabs
  3. Enter the password if the payload was encrypted (leave it empty otherwise)
  4. Decode, then read the message, download the file or check the anomaly score

Document Detection Methods: Auto-Detect and Six Readers

MethodWhat it readsEvidenceBest For
Auto-DetectTries the six methods in order and returns the best result: a file, then text with a flag, then text, then encrypted data, then binaryReads only the formats this site's Hider writesDocuments from the Hider
Custom XML PartscustomXml/ep_payload.xml (or any customXml part with an <ep:data> element, or the part named by the stegotoolkit relationship)Kept by python-docx and python-pptx re-saves, dropped by openpyxl (Word and LibreOffice not tested)Default Hider output
ZIP CommentA ZIP comment that starts with EP_STEGO_V1:Dropped by every re-save tested; 48,750 bytes at mostSmall messages, CTF files
XML Attributeep:d="EP_STEGO_V1:index:chunk" attributes on paragraphs, sheets or slide idsKept by python-docx and python-pptx re-saves, dropped by openpyxlDocuments with many paragraphs or slides
Hidden TextA run with the hidden-font property whose text starts with EP_STEGO_V1:Kept by a python-docx re-save; DOCX onlyWord documents
Revision TrackingA tracked insertion (<w:ins>) whose text starts with EP_STEGO_V1:Kept by a python-docx re-save; DOCX onlyWord documents
ZIP Extra FieldCentral-directory extra fields with the private tag 0x4550Dropped by every re-save testedFiles that were sent as they were

What the Document Extractor Reads

This Extractor reads the six formats the Document Hider on this site writes: a custom XML part, a ZIP comment, ep attributes, a hidden run, a tracked insertion and ZIP central-directory extra fields. Auto-Detect tries them in that order and shows the best result: a recognised file ranks first, then text that contains a flag, then other text, then encrypted data, then binary. It does not read data hidden by other tools, and it cannot tell you that a document is clean, only that none of these six formats was found.

A candidate is accepted when it matches this tool's marker (EP_STEGO_V1: or the ep:data element or the 0x4550 tag) and format checks. These checks identify a likely payload; they do not show that its contents are intact, and they are not a checksum of the message: an unencrypted message that was changed afterwards is read as it now stands, while a changed encrypted payload fails AES-GCM authentication when you enter the password.

Finding Hidden Text in a Word Document

People search for ways to find hidden text in a Word document. In Forensic mode the Hidden Text tab lists every run that is hidden with the vanish property (the bare form and the explicit on forms w:val="1" and "true"), every run coloured white and every run with a font size under 2 pt, with its text. It reads the document XML directly, so it shows text whoever added it, not only this tool's own payload.

The Custom Parts tab lists every customXml part and custom relationship in the package, the Namespaces tab lists the XML namespaces in use, the Entropy tab shows how random each part is, and the Strings tab lists readable strings with flag patterns highlighted. None of them proves that something is hidden: an ordinary document can have custom parts and unusual namespaces.

Passwords and What You See

The Extractor decrypts only when you enter a password. A payload stored without a password is shown directly, and a password typed for it is ignored. An encrypted payload opened with no password or a wrong one is shown as the stored encrypted bytes and labelled encrypted; wrong password, damaged data and missing password give the same result, so the screen cannot say which applies.

What Auto-Detect Looks For

OrderMethodWhat it looks forHow a find is confirmed
1Custom XML PartscustomXml/ep_payload.xml, any customXml part with an <ep:data> element, or the part named by the stegotoolkit relationship in _rels/.rels<ep:data> holds valid base64
2ZIP CommentThe ZIP commentIt starts with EP_STEGO_V1: followed by valid base64
3XML Attributeep:d attributes in word/document.xml, xl/workbook.xml or ppt/presentation.xmlThe ep namespace is declared and the chunks join into valid base64
4Hidden TextA run with the vanish property in word/document.xml (DOCX only)Its text starts with EP_STEGO_V1:
5Revision TrackingA <w:ins> element in word/document.xml (DOCX only)Its text starts with EP_STEGO_V1:
6ZIP Extra FieldCentral-directory extra fieldsBlocks with the tag 0x4550 join into a payload

The Anomaly Score (Measured on a Reference File)

The score adds up to six parts: custom parts and relationships (up to 25: 15 for a custom relationship plus 10 when a Custom XML payload is found), ZIP comment (15), ep attributes (20), hidden text and revisions (15: 10 for hidden text and 5 for a tracked insertion), ZIP extra field (15) and payload quality (10: a recognised file or a flag). Scores below are for the same generated 100-paragraph DOCX with a short plain-text message (no flag) hidden with each method; a clean document scores 0.

Method used to hide the messageScore
None (clean document)0
Custom XML Parts25
ZIP Comment15
XML Attribute20
Hidden Text10
Revision Tracking15
ZIP Extra Field15

What You See for Each Password Situation

PayloadPassword typedResult
Not encryptedNoneThe message
Not encryptedAnyThe message (the password is ignored)
EncryptedNoneThe stored encrypted bytes, labelled encrypted
EncryptedWrongThe same stored encrypted bytes
EncryptedRightThe message, marked as decrypted

The Forensic Mode Tabs

TabWhat it showsReads data from other tools?
ZIP StructureEvery ZIP entry with sizes, comments and extra fields; entries carrying the 0x4550 tag are markedLists any ZIP
Custom PartsEvery customXml part and custom relationshipYes, lists any
NamespacesThe XML namespaces used in each part, marked standard or unusualYes, lists any
Hidden TextRuns that are hidden, white or under 2 pt, with their text (DOCX)Yes, lists any
EntropyHow random each part is (0 to 8 bits per byte)Yes, any part
StringsReadable strings from the XML parts, flag patterns highlightedYes, any part

Examples

Input: A DOCX made by the Hider with the message "Meet at the old bridge at 9pm." in Custom XML Parts, no password

Result: Auto-Detect finds customXml/ep_payload.xml, shows the 30 characters as text, and the anomaly score is 25 (custom relationship 15 plus the payload found there 10).

Meaning: The same message hidden in the ZIP comment scores 15 and in ep attributes 20. The score counts this tool's markers; it is not a measure of how well the data is hidden.

Input: The same message hidden with a password, opened with no password, then a wrong one, then the right one

Result: With no password and with a wrong one you get the same 79 stored bytes (31 plus the 48-byte wrapper), labelled encrypted. With the right password you get the 30-character message, marked as decrypted.

Meaning: The screen does not say whether the password was missing, wrong or the data damaged. A password typed for a message that was never encrypted is ignored and the message is shown.

Input: An ordinary DOCX made by python-docx that contains one run marked hidden

Result: Auto-Detect finds nothing and the score is 0, because the run does not start with EP_STEGO_V1:. The Forensic Hidden Text tab lists the run and its text.

Meaning: This is how to look at a document made by something else: the Extractor reads only its own formats, while the Forensic tabs show what is in the file.

Input: A leaked copy from a 10-recipient export, with the watermark_keys.json file loaded in Forensic mode

Result: The Extractor reads the watermark ID from the copy and names the recipient it was made for.

Meaning: This works only while the ID is still in the file. A re-save that dropped the ZIP comment or extra fields, if that is where it was hidden, removes the ID, and the key file alone cannot identify the copy.

Input: A document hidden with Revision Tracking

Result: Auto-Detect returns the correct message but names Hidden Text as the method, because the tracked insertion holds a hidden run with the same marker and the Hidden Text reader gets there first. Choosing Revision Tracking in Standard mode names it.

Meaning: The payload is the same either way; only the label of the method differs.

How the Document Extractor Works

Read the document as a ZIP

JSZip opens the file in your browser. A file that is not a ZIP package is refused with a message.

Try the readers

Auto-Detect runs the six readers in order; in Standard mode you pick one. Each looks only for this tool's marker.

Choose the best candidate

Of the candidates found, a recognised file ranks first, then text with a flag, then text, then encrypted data, then binary.

Decrypt and unwrap

If you typed a password and the stored bytes have the encrypted layout, AES-256-GCM is decrypted. The file-name frame is then removed, and Reed-Solomon is repaired first if you ticked it in Forensic mode and the data starts with its header.

Interpret

The result is classified as text, a file with a known signature, encrypted-looking data or unrecognised bytes, and flag patterns are highlighted.

Score and analyse

The anomaly score adds up the markers found. In Forensic mode the ZIP, custom part, namespace, hidden text, entropy and strings tabs read the package directly.

What the results mean

ResultWhat it meansWhat to do
Message or file with the method namedA candidate carried this tool's marker. Text is shown with any flags highlighted; a recognised file is offered as a download under its original name when the Hider stored one.Read it, or download it.
Encrypted bytes, labelled encryptedThe payload has the encrypted layout and no password, or the wrong one, was used.Enter the password and decode again.
Unrecognised binaryA payload was found but it is neither readable text nor a known file type.It may be a file without a signature; download it and inspect it.
Nothing found, score 0None of the six markers is in the file.This does not prove the document is clean; use the Forensic tabs to look at it.
A score above 0 without a payloadThe file has a custom relationship, a ZIP comment or other signs, but no readable payload (for example a comment that does not start with the marker).Open the ZIP Structure and Custom Parts tabs.
Reed-Solomon recovery noteThe parity was applied and the number of repaired bytes is shown.Check the result: over the limit the repair usually fails, and a rare miscorrection is possible (a password makes AES-GCM expose it).

Limitations

  • Only the six formats the Document Hider writes are read. Data hidden by other tools, or in other places, is not found by Auto-Detect.
  • DOCX, XLSX, PPTX and ODT only; the format is taken from the file extension. A document that Office encrypted with a password is refused. Files above 200 MB (50 MB on a phone) are refused.
  • An unencrypted payload is checked only by its marker and length, so a changed message can be returned without a warning; encrypted payloads fail authentication instead.
  • A wrong password, a missing password and damaged encrypted data give the same result, so the screen cannot say which applies.
  • A re-save can remove the data before you get the file. In our tests python-docx and python-pptx re-saves kept Custom XML Parts and XML Attribute data, an openpyxl re-save kept none, and every re-save dropped the ZIP comment and extra fields. Word, LibreOffice and Google Docs were not tested.
  • The anomaly score counts this tool's markers only; it is not a general steganalysis measure, and a low score does not mean a document is free of hidden data.
  • The Hidden Text tab finds the hidden-font property, white text and text under 2 pt; text hidden in other ways is not found.
  • Key-derivation time on phones was not measured.

Privacy

The document is read and decoded in your browser tab (a Web Worker, JSZip and the Web Crypto API) and is not uploaded. Usage statistics may record which options were used, never the document, the extracted data or the password. The hosting provider keeps ordinary request logs for page loads.

Which Tool Next?

Frequently Asked Questions

What documents does the Extractor read?

DOCX, XLSX, PPTX and ODT files (all ZIP packages), up to 200 MB (50 MB on a phone). The format comes from the file extension. A document that Office encrypted with a password is not a ZIP and cannot be read here.

Can it read data hidden by other tools?

No. Auto-Detect and the six readers look only for the markers this site's Hider writes (EP_STEGO_V1:, the ep namespace, tag 0x4550). A document hidden by another program is not read, and an empty result does not prove a document is clean. The Forensic tabs can still show unusual parts, hidden runs and strings from any document.

How do I find hidden text in a Word document?

Upload it, switch to Forensic mode and open the Hidden Text tab. It lists runs marked hidden (<w:vanish/>, including the explicit on forms w:val="1" and "true"), white-coloured text and text under 2 pt, whoever put them there, with the text of each. Text hidden by a custom style or placed off the page is not detected. Word's own Show/Hide option reveals ordinary hidden text too.

Is my document uploaded?

No. JSZip and the Web Crypto API process the document in your browser tab; it is not sent to a server. Usage statistics may record which options were used, never your document.

What if nothing is found?

Auto-Detect returns no payload and the anomaly score stays at 0 for a document with none of this tool's markers. Try each method on its own in Standard mode, and check the password: a payload that was written with another tool, or removed by a re-save (ZIP Comment and ZIP Extra Field are lost by any re-save), cannot be read.

Why is the output garbled?

The payload is encrypted. With no password, or a wrong one, the Extractor shows the stored encrypted bytes and labels them encrypted; it does not raise an error. Enter the password used when hiding. A password typed for a payload that was never encrypted is ignored and the message is shown normally.

Can it find CTF flags automatically?

Yes. The decoded text is scanned for FLAG{…}, HTB{…}, picoCTF{…}, CTF{…}, CHTB{…}, THM{…}, VULNHUB{…} and rootme{…}, and for any 2-8 letter upper-case prefix followed by braces. Hits are highlighted. The Strings tab in Forensic mode scans every XML part of the document the same way.

What does Reed-Solomon Recovery do?

If the Hider added Reed-Solomon parity, tick this option in Forensic mode: the Extractor repairs up to 5, 10 or 15 changed bytes per 223-byte block (RS-10, RS-20, RS-30) and then removes the parity. It cannot rebuild data that a program dropped when it saved the file. It works only on payloads hidden without a password: the Hider adds the parity before encryption, so damaged bytes of a password-protected payload fail the AES-GCM check first.

What is the anomaly score?

A number from 0 to 100 that adds up the signs of this tool's six methods in the file: custom parts and relationships (up to 25: 15 for a custom relationship plus 10 when a Custom XML payload is found), a ZIP comment (15), ep attributes (20), hidden or tracked data (15), extra fields (15) and the quality of what was recovered (10). It counts these markers only. A clean document scores 0, and a low score never means a document is free of hidden data.

How does watermark attribution work?

If a copy was made with the Hider's per-recipient export, switch to Forensic mode, upload the watermark_keys.json that came with the ZIP, and decode the leaked copy. When the copy still carries its watermark ID the Extractor names the matching recipient. The key file alone cannot identify a copy whose ID has been removed.

Related Tools