# Security Implications of the Design.md Export Feature: Path Traversal and Data Leakage Risks

> Explore security implications of the Design.md export feature including path traversal risks, stdout data leakage, and unprotected stdin streams. Learn how to mitigate these exposures.

- Repository: [Google Labs Code/design.md](https://github.com/google-labs-code/design.md)
- Tags: security-analysis
- Published: 2026-07-02

---

**The Design.md export command is intentionally read-only and deterministic, but creates potential security exposures through unsanitized file path arguments, stdout data leakage, and unprotected stdin streams that could be poisoned in CI environments.**

The `export` command in the Design.md CLI transforms DESIGN.md files into token formats like Tailwind CSS, JSON, DTCG, and CSS variables. While the implementation follows a bounded execution flow that prevents arbitrary code execution, the security implications of its file I/O handling and output mechanisms require careful consideration when operating in shared or automated environments.

## File System Exposure and Path Traversal Vulnerabilities

The export command does not sanitize or restrict the `--file` argument, creating a path traversal risk when processing the input DESIGN.md file. In [`packages/cli/src/commands/export.ts`](https://github.com/google-labs-code/design.md/blob/main/packages/cli/src/commands/export.ts) (lines 23-44), the command defines three arguments (`file`, `format`, `prefix`) using the `citty` framework, accepting any string value without validation.

When executing the export, the code calls `readInput` from [`packages/cli/src/utils.ts`](https://github.com/google-labs-code/design.md/blob/main/packages/cli/src/utils.ts) on line 61 of [`export.ts`](https://github.com/google-labs-code/design.md/blob/main/export.ts). This utility supports both file paths and the special `-` token for stdin input. Errors during file reading are caught as `FileReadError` on lines 62-67, but the underlying implementation trusts any path supplied by the user.

This design allows an attacker with influence over the `--file` parameter to read any readable file on the host file system. For example, supplying `--file /etc/passwd` or other sensitive system paths could expose critical configuration data. Users must ensure that only trusted paths are supplied, particularly in CI scripts or shared environments where argument injection is possible.

## Data Confidentiality and Information Leakage

Exported token sets may embed proprietary design values including internal color codes, spacing tokens, and branding-specific styling that should remain confidential. The command writes all output to `stdout` on lines 82, 93, 104, and 115 of [`export.ts`](https://github.com/google-labs-code/design.md/blob/main/export.ts), which creates two distinct confidentiality risks.

First, if the export command runs in an environment where stdout is logged or intercepted—such as public CI/CD logs or container orchestration platforms—sensitive design data could be unintentionally exposed to unauthorized parties. Second, the JSON-encoded error messages printed during handler failures (lines 76-92 and 98-104) may leak internal file paths or system information.

Treat all export output as confidential and avoid printing tokens in publicly accessible logs. Consider piping output directly to secure destinations rather than capturing it in environment variables or log buffers.

## Format Validation and Injection Prevention

The command mitigates code execution risks through strict format validation. On lines 49-55 of [`export.ts`](https://github.com/google-labs-code/design.md/blob/main/export.ts), the supplied `--format` value is checked against a closed `FORMATS` enum. Invalid values trigger a JSON-encoded error message and exit code 1, preventing the instantiation of unknown or malicious format handlers.

Each emitter handler—including `TailwindEmitterHandler` in [`packages/cli/src/linter/tailwind/handler.ts`](https://github.com/google-labs-code/design.md/blob/main/packages/cli/src/linter/tailwind/handler.ts), `TailwindV4EmitterHandler` in [`packages/cli/src/linter/tailwind/v4/handler.ts`](https://github.com/google-labs-code/design.md/blob/main/packages/cli/src/linter/tailwind/v4/handler.ts), `DtcgEmitterHandler` in [`packages/cli/src/linter/dtcg/handler.ts`](https://github.com/google-labs-code/design.md/blob/main/packages/cli/src/linter/dtcg/handler.ts), and `CssVarsEmitterHandler` in [`packages/cli/src/linter/css-vars/handler.ts`](https://github.com/google-labs-code/design.md/blob/main/packages/cli/src/linter/css-vars/handler.ts)—implements a pure-functional `execute` method. These handlers perform only data transformations and do not invoke external services or perform I/O beyond writing to stdout, limiting the attack surface to the initial file read operation.

## STDIN Handling and Pipeline Risks

When using the `-` token to read DESIGN.md content from stdin, the command becomes vulnerable to **STDIN poisoning**. A malicious upstream process in a pipeline could feed crafted content designed to exploit downstream consumers of the export output, even though the `lint` function called on line 70 of [`export.ts`](https://github.com/google-labs-code/design.md/blob/main/export.ts) validates syntax before processing.

The linting step itself is sandboxed and does not execute user code, but the content validation occurs after the data has already entered the pipeline. In automated workflows where stdin comes from curl commands or external sources, verify the integrity of the input stream before passing it to the export command.

## Secure Usage Examples

When running the export command in production environments, use these patterns to minimize security exposure:

```bash

# Safe: Export to file directly, avoid logging stdout

designmd export my-design.md --format css-tailwind > ./secure-output/theme.css

# Risky: Capturing output in variable may expose in process lists

json=$(designmd export my-design.md --format json-tailwind)

# Safe: Pipe from trusted source with integrity checks

cat verified-design.md | designmd export - --format css-vars --prefix brand-

```

## Summary

- **Path traversal vulnerability**: The `--file` argument accepts any readable path without sandboxing, potentially exposing sensitive system files if user input is not properly filtered.
- **Information disclosure**: Exported design tokens written to stdout may leak proprietary data if captured in public logs or insecure environments.
- **Format safety**: A closed enum and pure-functional emitter handlers prevent arbitrary code execution and limit the attack surface to approved transformation logic.
- **Pipeline risks**: STDIN input mode introduces poisoning possibilities when upstream processes are untrusted or compromised.

## Frequently Asked Questions

### Can the export command execute arbitrary code on my system?

No. According to the Design.md source code, the export feature uses a closed `FORMATS` enum (lines 49-55 of [`packages/cli/src/commands/export.ts`](https://github.com/google-labs-code/design.md/blob/main/packages/cli/src/commands/export.ts)) to validate the `--format` argument, preventing instantiation of unknown handlers. The emitter handlers in `packages/cli/src/linter/` are pure-functional transformations that do not invoke external processes or eval user content.

### Is it safe to run the export command on untrusted DESIGN.md files?

While the linting process in [`packages/cli/src/linter/index.ts`](https://github.com/google-labs-code/design.md/blob/main/packages/cli/src/linter/index.ts) is sandboxed and does not execute code, you should treat the `--file` path as a privileged operation. The command can read any file path accessible to the process user, including system files like `/etc/passwd`, so ensure the path argument comes from a trusted source and cannot be manipulated by attackers.

### How do I prevent sensitive design tokens from leaking in CI logs?

Avoid echoing or logging the output of the export command in public CI environments. Instead of capturing the output in a variable or printing it directly, pipe the results immediately to secure storage. For example: `designmd export design.md --format json-tailwind > secure-output.json` rather than `json=$(designmd export design.md --format json-tailwind)`.

### Why does the export command exit with code 0 even when linting finds issues?

As noted in the comments on lines 118-120 of [`packages/cli/src/commands/export.ts`](https://github.com/google-labs-code/design.md/blob/main/packages/cli/src/commands/export.ts), successful exports intentionally exit with code 0 regardless of lint findings. This design separates lint warnings from export failures, but may mask security-relevant lint errors unless you explicitly check the lint output separately before running the export command.