Por qué un PDF puede ejecutar código
La especificación del PDF tiene un capítulo dedicado a las acciones: cosas que el lector hace solo. Dónde se enganchan, por qué un enlace también es una y cómo se quitan de verdad.
A nadie se le ocurre que un documento vaya a hacer algo. Lo abres, enseña páginas, lo cierras. Pero la especificación del PDF dedica un capítulo entero a lo que llama acciones: instrucciones que el lector ejecuta por su cuenta, sin que nadie pulse nada. De ahí sale que un archivo con forma de taco de folios pueda correr JavaScript, pedirle a tu ordenador que abra un programa o mandar lo que escribes en un formulario a un servidor del que no habías oído hablar.
reader.me ya sabe quitar esa capa: quitar el contenido activo de un PDF la elimina en el navegador y deja las páginas donde estaban. Lo que viene ahora es lo que la herramienta mira por dentro, porque lo interesante es el formato, no el botón.
La página es solo una de las cosas que hay en el archivo
Un PDF es un conjunto de objetos con un catálogo en la raíz que dice dónde está cada uno. Las páginas son objetos. Las fuentes también. Y los marcadores, la definición del formulario, los perfiles de color y —esto es lo que casi nadie tiene en la cabeza— diccionarios que dicen cuando pase esto, haz aquello.
El apartado 12.6 del estándar define toda la familia. Un diccionario de acción lleva un tipo, la clave /S, y lo demás depende de cuál sea. /S /JavaScript lleva código. /S /Launch, la ruta de un programa. /S /SubmitForm, la URL a la que se manda el contenido del formulario. No son añadidos raros de última hora: llevan ahí décadas.
Seis sitios de los que puede colgar una acción
Esto da más trabajo del que parece porque las acciones no viven en un único sitio ordenado. Se enganchan en seis puntos, y a un archivo le basta con uno:
- El árbol de JavaScript del documento. Código a nivel de documento, que corre al abrir el archivo sin que hagas nada.
- La acción de apertura. Una acción en el catálogo, que salta en cuanto se muestra el documento.
- Las acciones adicionales del documento. Al cerrar, al guardar, antes y después de imprimir.
- Las acciones adicionales de cada página. Al entrar en la página y al salir de ella.
- La acción de una anotación. El rectángulo clicable, el ratón por encima, el foco.
- Las acciones de un campo de formulario. Al teclear, al validar, al calcular, al perder el foco.
Si se te escapa uno, no has limpiado el archivo: has limpiado casi todo. Una acción colgada de una página, en un documento con el catálogo impecable, se ejecuta igual.
La trampa: un enlace también es una acción
Aquí es donde un limpiador con demasiadas ganas hace más daño que lo que quita. Un hipervínculo normal en un PDF es una anotación /Link con una acción enganchada, de tipo /URI. El índice que te lleva al capítulo cuatro también es una acción, de tipo /GoTo. Si borras todas las acciones te llevas por delante el código, los enlaces que abren programas y todos los hipervínculos y saltos internos que puso quien escribió el documento.
Así que la decisión no puede tomarse por dónde está la acción. Se toma por de qué tipo es.
Se van: /JavaScript, /Launch, /SubmitForm, /ImportData, /GoToR y /GoToE (que mandan al lector a abrir otro documento, remoto o incrustado) y los que arrancan el motor multimedia: /Movie, /Sound, /Rendition, /RichMediaExecute.
Se quedan: /URI, /GoTo, /Named, /Thread, /Trans, /Hide, /SetOCGState, /GoTo3DView — navegación y presentación, nada que ejecutar. Y si aparece un tipo que no reconocemos, también: romper un documento por exceso de celo es un mal cambio.
De ahí salen dos detalles fáciles de pasar por alto. La acción de apertura no siempre es una acción: la especificación permite que sea un destino a secas, un array que significa «ábreme por la página siete», y eso no ejecuta nada. Y las acciones se encadenan: la clave /Next cuelga una acción de otra, de modo que un /URI inocente puede venir arrastrando un JavaScript detrás. A cada acción que sobrevive se le recorre la cadena y se le poda.
Quitar la entrada no es quitar la cosa
Esta es la parte que separa limpiar de parecer limpio.
Si borras del catálogo la clave del JavaScript, desenganchas el código de la estructura del documento. No lo sacas del archivo. Los escritores de PDF vuelcan todos los objetos que llevan en la mano, los referencie alguien o no. Abre los bytes resultantes en un editor de texto y ahí está el script, en un objeto al que ya no apunta nadie: invisible en el panel de propiedades, perfectamente legible para quien mire el archivo.
Por eso cada acción que se quita se borra del documento de verdad, junto con su carga: el stream con el código, la cadena /Next y la ruta del ejecutable en un /Launch. Nuestro test no mira el catálogo. Busca el código entre los objetos del archivo de salida, que es la única comprobación que significa algo.
Lo que un archivo limpio no es
Limpiar no convierte un archivo peligroso en seguro. Quita lo que un lector podría ejecutar. No toca lo que una página pueda decir.
Un PDF que enseña una pantalla de acceso creíble y te pide la contraseña es igual de creíble con hasta la última línea de JavaScript fuera. Lo mismo con una factura falsa que lleva el número de cuenta cambiado. Ahí el problema son las palabras, y ninguna limpieza estructural llega hasta ellas. Quédate con «este archivo ya no ejecuta nada», no con «este archivo está bien».
Los adjuntos van en una casilla aparte por un motivo parecido. Un archivo incrustado no es contenido activo —nadie lo ejecuta al abrir el documento— pero es la vía habitual de que viaje algo más. La herramienta te los enseña, deja marcada la casilla de conservarlos y decides tú. Si los conservas, lo que lleven dentro sigue dentro.
El círculo que esto cierra
Nuestra herramienta de metadatos lleva tiempo sabiendo decirte que un documento lleva JavaScript incrustado o una acción de apertura: lo que un PDF cuenta de sí mismo lo informa junto a los autores y las fechas. Lo que no podía era hacer nada al respecto. Si alguna vez viste ese aviso y te quedaste con la duda de cuál era el paso siguiente, es este.
Va bien con las dos costumbres de al lado: mirar qué revela tu PDF sobre ti antes de que salga de tus manos y borrar los metadatos de verdad en vez de taparlos. La idea de fondo es la misma: un documento guarda más de lo que se lee.