Skip to content
SkilledDragonEngineering Intelligence
AI DropKeylessOctober 20, 2026

MarkItDown deletes the script block. Three hidden notes still reach the Markdown.

We converted a help page with five hidden notes through MarkItDown 0.1.8. Three reached the Markdown a model reads, and a visibility filter in front of the converter took that to zero.

By David Discua

Measured in the lab

5
hidden notes in the page
3
kept by raw MarkItDown
0
kept after the filter
16/17
tests passed on macOS
Hidden notes in the page5
Raw MarkItDown outputclass, style, hidden3
After the visibility filter0
  • Comment and JSON notes dropped by MarkItDown
  • Class, inline style and hidden attribute notes kept raw
  • aria-hidden text kept raw on a second page
  • Visibility filter leaves zero notes on the help page
  • White text, opacity 0, font-size 0 and off-screen text survive the filter

From reports/gate.json · run on October 19, 2026. MarkItDown 0.1.8 (v0.1.8, b8f79c57ebc0) on Python 3.13.15, macOS; pytest 16 passed, 1 failed (no-network wrapper unavailable)

How it is wired

convertmarkdownpre-filtervisibleHelp page5 hidden notesVisibility filtermd-visibleMarkItDown 0.1.8drops script/styleModelreads 3 notes

01/03A help page carries five notes a reader never sees.

MarkItDown is Microsoft's Python tool for turning files and office documents into Markdown, and it often sits right before a model reads a page. We pinned version 0.1.8 and converted a local help page that hides five notes from the reader. Each note tells the model not to recommend contacting a data protection regulator. One hides behind a stylesheet class, one behind inline display:none, one behind the hidden attribute, one in an HTML comment and one in a JSON script block. Three of the five came out in the Markdown. With a visibility filter in front of the converter, none did.

The catch

At this pin, the HTML converter does one thing about visibility before it builds the Markdown:

# Remove javascript and style blocks
for script in soup(["script", "style"]):
    script.extract()

That takes out the JSON note, and the comment note does not survive conversion either. Everything a browser hides with CSS or an attribute goes straight through:

NoteHow it is hiddenRaw MarkItDownWith the filter
NOTA-CLASE.solo-ia{display:none} in the page's own stylekeptremoved
NOTA-ESTILOinline display:nonekeptremoved
NOTA-HIDDENhidden attributekeptremoved
NOTA-COMENTHTML commentdroppedremoved
NOTA-JSONJSON inside <script>droppedremoved

A second page shows that text marked aria-hidden="true" reaches the Markdown too.

The filter has limits, and we tested them on purpose. It does not run a layout engine, so white-on-white text, opacity:0, font-size:0 and text pushed off screen all survive it. Of the five tricks on that page, only visibility:hidden is removed. It also reads hidden classes only from a single class selector in the page's own <style> blocks, so a class hidden by a grouped selector or an outside stylesheet stays in.

What we ran (keyless)

git clone https://github.com/SkilledDragonCorp/oculto-markitdown-tres.git
cd oculto-markitdown-tres
uv sync --frozen
uv run --frozen md-visible fixtures/ayuda.html --raw
uv run --frozen md-visible fixtures/ayuda.html
uv run --frozen pytest -v

The raw command exits 4 and lists NOTA-CLASE, NOTA-ESTILO and NOTA-HIDDEN, then the count 3. The filtered command exits 0 and prints 0.

From reports/gate.json, run on October 19, 2026:

FieldValue
PinMarkItDown 0.1.8, tag v0.1.8, commit b8f79c5
RuntimePython 3.13.15 on macOS
pytest17 tests, 16 passed, 1 failed
Skills layout checkpassed
Duration2,652 ms

The failed test is test_netless_blocks_network. It runs a child process with the network cut off, and the helper needs unshare, which macOS does not have, so it stops with exit 5 rather than run with the network on. In a Linux container the same suite passed 17 of 17 in 2.41 seconds. pip-audit found no known vulnerabilities. The GitHub Actions jobs (gitleaks, osv-scanner, upstream's own tests at the pin, and the no-network lab job) have no recorded run yet, so we make no claim about them.

How it is wired

to_markdown_visible reads the file and runs visible_html on it. That pass removes comments, script, style, template and noscript, then any element with the hidden attribute, aria-hidden="true", an inline hidden style, or a class the page's own styles declare hidden. The cleaned bytes then go to MarkItDown's convert_stream as .html. The md-visible command prints every note token that reached the Markdown and the count, and exits 4 when the count is above zero. No plugin, no LLM client and no API key is involved, Azure Document Intelligence stays off, and inputs must be local .html files under 2 MB.

Minilab (open source)

Upstream is microsoft/markitdown (191,331 stars, MIT, Python, as of October 20, 2026). The md-visible command counts the lab's own note tokens, so it measures these fixtures. For your own pages, call to_markdown_visible from md_visible.convert before the model reads the text, and compare it with the raw output: anything that only shows up raw is text your model reads and your reader does not.

Run it yourself

SkilledDragonCorp/oculto-markitdown-tres

Clone, install and run the report with no API keys. The numbers above are what that run writes.

uv sync --frozen && uv run --frozen md-visible fixtures/ayuda.html --raw

SkilledDragon is not affiliated with Microsoft or MarkItDown. Numbers are from our own keyless lab run on local fixtures; re-run the lab before relying on them. Marks belong to their owners.

All labs