Skip to content
reader.me

Why a PDF can run code at all

The PDF format has a chapter about actions: things a reader does on its own. Where they hang, why a hyperlink is one too, and what it takes to remove them for real.

AGAntonia González · August 16, 2026 · 6 min read

Nobody expects a document to do anything. You open it, it shows pages, you close it. But the PDF specification devotes a chapter to something called actions: instructions the reader carries out by itself, with nobody clicking anything. That chapter is why a file shaped like a stack of paper can run JavaScript, ask your computer to launch a program, or post what you typed into a form to a server you’ve never heard of.

reader.me can now take that layer out: remove active content from a PDF strips it in the browser and leaves the pages alone. What follows is what the tool is actually looking at, because the interesting part is the format, not the button.

The page is only one of the things in the file

A PDF is a set of objects with a catalog at the root pointing at the rest. Pages are objects. Fonts are objects. So are bookmarks, form definitions, colour profiles, and — this is the part almost nobody has a mental model for — dictionaries that say when something happens, do this.

Section 12.6 of the standard defines the whole family. An action dictionary has a type, written /S, and everything else depends on which type it is. /S /JavaScript carries code. /S /Launch carries the path of a program. /S /SubmitForm carries the URL the form contents go to. They aren’t exotic extensions bolted on later; they’re part of what a PDF is allowed to be, and they’ve been there for decades.

Six places an action can hang from

The reason this is more work than it sounds is that actions don’t live in one tidy place. They attach at six different points, and a file only needs one of them:

  • The document’s JavaScript name tree. Code registered at document level, which runs when the file opens. No interaction required.
  • The open action. A single action on the catalog, fired the moment the document is displayed.
  • The document’s additional actions. On close, on save, before printing, after printing.
  • A page’s additional actions. When you scroll into that page, and when you leave it.
  • An annotation’s action. The clickable rectangle. Also mouse-over, mouse-out, focus.
  • A form field’s actions. On keystroke, on validate, on calculate, on losing focus.

Miss one and you haven’t cleaned the file, you’ve cleaned most of it: a page-entry action in a document with a spotless catalog still runs.

Here’s where an over-eager cleaner does more damage than the thing it removes. A normal hyperlink in a PDF is a /Link annotation with an action attached, and that action’s type is /URI. The table of contents that jumps you to chapter four is an action as well, type /GoTo. Strip every action in the document and you’ve deleted the code, the launch links and every hyperlink and every internal jump the author put in.

So the decision can’t be made by where the action lives. It has to be made by what type it is.

Removed: /JavaScript, /Launch, /SubmitForm, /ImportData, /GoToR and /GoToE (which send the reader off to open another document, remote or embedded), and the multimedia executors — /Movie, /Sound, /Rendition, /RichMediaExecute.

Kept: /URI, /GoTo, /Named, /Thread, /Trans, /Hide, /SetOCGState, /GoTo3DView — navigation and presentation, nothing that executes. Anything with a type we don’t recognise is kept too, on the principle that breaking a document to be thorough is a bad trade.

Two details fall out of this that are easy to get wrong. The open action isn’t always an action: the specification also lets it be a plain destination, an array meaning “open at page seven”, and that executes nothing, so it stays. And actions chain. A /Next key hangs one action off another, so an innocent /URI can be towing JavaScript behind it. Every surviving action gets its chain walked and pruned.

Deleting the entry is not deleting the thing

This is the part that separates a cleaner from a file that merely looks clean.

Removing the JavaScript key from the catalog unlinks the code from the document structure. It does not remove it from the file. The object holding that code is still an object the writer knows about, and PDF writers serialise the objects they’re holding whether or not anything points at them any more. Open the resulting bytes in a text editor and the script is right there, sitting in an object nothing references — invisible to a reader’s properties panel, perfectly readable to anyone who looks at the file itself.

So each removed action gets deleted from the document proper, along with its payload: the code stream, the chained /Next, and the executable path in a /Launch. Our test for this doesn’t check the catalog. It searches the objects of the output file for the code, which is the only check that means anything.

What a cleaned file is not

Cleaning does not turn a dangerous file into a safe one. It removes what a reader could execute. It does not touch what a page can say.

A PDF that shows a convincing login page and asks for your password is exactly as convincing with every last line of JavaScript stripped out of it. Same for a fake invoice with the wrong bank account. The threat there is the words, and no amount of structural cleaning reaches them. Treat the result as “this file won’t run anything”, not “this file is fine”.

Attachments sit in their own box for related reasons. A file embedded inside a PDF isn’t active content — nothing executes it when you open the document — but it’s the usual way something else travels along. The tool lists them and leaves them ticked to keep by default, and you decide. If you keep one, whatever is inside it is still inside it.

The circle this closes

Our metadata tool has been able to tell you a document carries embedded JavaScript or an open action for a while: what a PDF says about itself reports it alongside authors and timestamps. It just couldn’t do anything about it. If you ever ran that check, saw the warning and wondered what the next step was, this is it.

Worth pairing with the habits either side: check what your PDF reveals about you before anything leaves your hands, and strip metadata properly rather than hiding it. Same principle each time — a document holds more than the part you can read.

Explore by category