Skip to content

Path traversal / arbitrary local file read via @@x-template (and l10n.yaml) template path #91

Description

@Forbiddem

Summary

Parser.resolveTemplatePath() passes a workspace-controlled path straight to fs.readFileSync without any containment check, so a crafted .arb file (or l10n.yaml) can make the extension read any file the editing user can open, outside the project.

  • Version: 0.2.2 (HEAD a6fa5a3)
  • Source: the @@x-template field of an .arb file, or arb-dir / template-arb-file in l10n.yaml
  • Sink: src/messageParser.ts:243fs.readFileSync(templatePath, "utf8")
  • Resolve: src/messageParser.ts:207-218 — no .. rejection, no workspace containment, absolute paths returned as-is

Steps to reproduce

  1. In any Flutter/ARB project, set the template field of an .arb file:
    { "@@locale": "es", "@@x-template": "../../../../../../../../../../etc/passwd" }
    (path.join clamps surplus .. at the filesystem root, so this lands on /etc/passwd regardless of where the repo is cloned; an absolute path works too.)
  2. Open the project in VS Code with the ARB Editor extension installed and open the .arb file.
  3. The extension's parser runs and calls fs.readFileSync("/etc/passwd") — a file entirely outside the workspace.

Impact

  • Arbitrary local file read. Any file readable by the user can be opened by the extension as a side effect of editing a repository.
  • Disclosure channel. For JSON-with-string-values targets, the top-level keys are echoed into the Problems panel as Missing messages from template: <keys> (src/diagnose.ts), surfacing file contents (key names) to the editing user — useful for exfiltration via a repo the attacker later inspects, or simply for tricking a victim.
  • Extension-host DoS (sub-case). The read is synchronous and follows symlinks; pointing the template at /dev/zero, a FIFO, or a multi-GB file blocks the extension host.

The same unchecked path also reaches the sink through the l10n.yaml (arb-dir + template-arb-file) branch.

Suggested fix

Resolve the candidate path and reject anything that escapes the workspace folder (fall back to the document directory when there is no workspace folder). Legitimate in-project templates are unaffected. PR attached.

This was reported through Google's VRP and closed as out of scope for that program; filing here so the project can fix it directly.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions