PDF Obfuscation against arXiv's TeX Source
Policies
Zhongtang Luo, Jianting Zhang, Zheng Zhong
Purdue University
$\LaTeX$
$\text{Lua}\LaTeX$
How does arXiv (mis)detect (Lua)LaTeX files?
$ mutool show test.pdf 509
509 0obj<</Author ()
/Title ()
/Subject ()
/Creator (LaTeX with hyperref)
/Keywords ()
/Producer (LuaTeX-1.21.0)
/CreationDate (D:19791231190000-05'00')
/ModDate (D:19791231190000-05'00')
/Trapped/False/PTEX.FullBanner (This is LuaHBTeX, Version 1.21.0 \(TeX Live 2025/nixos.org\))
>>endobj
$ mutool show test.pdf 509
509 0obj<</Author ()
/Title ()
/Subject ()
/Creator (LaTeX with hyperref)
/Keywords ()
/Producer (LuaTeX-1.21.0)
/CreationDate (D:19791231190000-05'00')
/ModDate (D:19791231190000-05'00')
/Trapped/False/PTEX.FullBanner (This is LuaHBTeX, Version 1.21.0 \(TeX Live 2025/nixos.org\))
>>endobj
$ mutool show test.pdf 509
509 0obj<</Author ()
/Title ()
/Subject ()
/Creator (LaTeX with hyperref)
/Keywords ()
/Producer (LuaTeX-1.21.0)
/CreationDate (D:19791231190000-05'00')
/ModDate (D:19791231190000-05'00')
/Trapped/False/PTEX.FullBanner (This is LuaHBTeX, Version 1.21.0 \(TeX Live 2025/nixos.org\))
>>endobj
tex?
latex?
text?
texas?
Field
Data
Undetected?
/Creator
TeX
/Creator
ConTeXt
/Creator
texture
/Creator
plaintext
/Creator
pdfTeXt
/Creator
texttext
/Creator
texttex
/Creator
tex-text
/Creator
tex
/Creator
texttex
/Creator
ConTeX
/Creator
TeX*
/Creator
*TeX
/Creator
LuaLaTeX
/Creator
pdfTeXs
/Creator
texas
/Creator
TeXas
/Creator
vertex
/Creator
paleocoretex
Field
Data
Undetected?
/Producer
pdfTeX-1.40.26
/Producer
pdfConTeXt-1.40.26
/Producer
texture
/Producer
plaintext
/Producer
pdfTeXt
/Producer
texttext
/Producer
texttex
/Producer
tex-text
/Producer
pdftex-1.40.26
/Producer
pdfConTeX-1.40.26
/Producer
pdfTeX*-1.40.26
/Producer
pdf*TeX-1.40.26
/Producer
pdfLuaLaTeX-1.40.26
/Producer
TeX
/Producer
pdfTeXs
/Producer
texas
/Producer
TeXas
/Producer
vertex
/Producer
paleocoretex
Field
Data
Undetected?
/Author
tex
/CreationDate
tex
/ModDate
tex
/PTEX.Fullbanner
tex
/Subject
tex
/Title
tex
/Trapped
tex
# --- Strip Document Info ---
print(f"[*] Metadata: {pdf.docinfo}")
print("[*] Stripping metadata...")
for key in list(pdf.docinfo.keys()):
del pdf.docinfo[key]
# --- Remove XMP Metadata if present ---
if "/Metadata" in pdf.Root:
del pdf.Root["/Metadata"]
print("[*] Removed XMP metadata stream")
$ pdffonts test.pdf
nametypeencodingembsubuniobject ID
------------------------------------ ----------------- ---------------- --- --- --- ---------
ENBKCE+LMRoman10-Regular CID Type 0C Identity-H yes yes yes 4 0
YCHXXL+CMMI10 Type 1 Builtin yes yes no 5 0
CZKGAS+CMR10 Type 1 Builtin yes yes no 6 0
YTYGMW+CMEX10 Type 1 Builtin yes yes no 7 0
FXXUVH+CMSY10 Type 1 Builtin yes yes no 8 0
EJASTL+CMR7 Type 1 Builtin yes yes no 9 0
Field
Data
Undetected?
Font's FontName
QMHNZG+CMR10
Font's FamilyName
Computer Modern
Font's FullName
CMR10
/FontName
/QMHNZG+CMR10
/BaseFont
/QMHNZG+CMR10
/BaseFont
/QMHNZG+CMMI10
/BaseFont
/QMHNZG+CMBX10
with open(renamed_font_path, "rb") as f:
new_font_data = f.read()
new_stream = pikepdf.Stream(pdf, new_font_data)
new_fontname = safe_fontname(fontname, replacement)
fontdesc[fontfile_key] = new_stream
fontdesc["/FontName"] = pikepdf.Name(new_fontname)
if "/BaseFont" in obj:
print(f"[+] Updating BaseFont from {obj['/BaseFont']}")
base_font = str(obj["/BaseFont"])
if "CM" in base_font:
new_base = safe_fontname(base_font, replacement)
obj["/BaseFont"] = pikepdf.Name(new_base)
print(f"[✓] Replaced: {fontname} → {new_fontname}")