Skip to content

🔒 HIGH: YAML Parsing Vulnerability - Potential DoS and XXE #720

Description

@sulthonzh

Description

The parseYamlWithFrontmatter() function in app/src/utils/yaml.tsx parses untrusted YAML without resource limits or security configurations, making it vulnerable to DoS attacks.

Context

  • File: app/src/utils/yaml.tsx:14
  • Component: YAML parser for project metadata
  • Severity: HIGH

Current Behavior

```typescript
export function parseYamlWithFrontmatter<F, C>(
yaml: string,
): {
frontmatter: F;
content: C;
} {
yaml = yaml.trim();
let contentList = yaml.split("---");
contentList = contentList.filter(Boolean);
const frontmatter = contentList[0];
const content = contentList[1];

return { frontmatter: YAML.parse(frontmatter), content: YAML.parse(content) };
}
```

This is vulnerable to:

  1. DoS via YAML anchors/aliases - Infinite loops, exponential memory usage
  2. DoS via deep nesting - Stack overflow
  3. DoS via large payloads - Memory exhaustion

Exploit Example

```yaml

anchor: &a

  • *a
  • *a
  • *a

... repeated 1000x - exponential blowup


```

Expected Behavior

YAML parsing should:

  1. Have strict size limits (max document size: 1MB)
  2. Have recursion depth limits (max depth: 20)
  3. Have anchor/alias limits (max references: 100)
  4. Parse with sandboxing if possible

Steps to Reproduce

// Create malicious YAML with exponential anchors
const maliciousYaml = `
---
&ref [*ref *ref *ref *ref *ref *ref *ref *ref *ref *ref *ref *ref *ref *ref]
---
`;
parseYamlWithFrontmatter(maliciousYaml);  // Hangs or crashes

Suggested Fix

```typescript
import YAML from "yaml";

// Configure limits
const MAX_YAML_SIZE = 1024 * 1024; // 1MB
const MAX_DEPTH = 20;
const MAX_ANCHORS = 100;

export function parseYamlWithFrontmatter<F, C>(
yaml: string,
): {
frontmatter: F;
content: C;
} {
// 1. Size validation
if (yaml.length > MAX_YAML_SIZE) {
throw new Error(`YAML document too large: ${yaml.length} bytes (max: ${MAX_YAML_SIZE})`);
}

yaml = yaml.trim();
let contentList = yaml.split("---");
contentList = contentList.filter(Boolean);
const frontmatter = contentList[0];
const content = contentList[1];

// 2. Parse with strict options
const options = {
strict: true,
maxAliasCount: MAX_ANCHORS,
// Use the yaml library's security features
};

return {
frontmatter: YAML.parse(frontmatter, options) as F,
content: YAML.parse(content, options) as C
};
}
```

Alternative: Use a more secure YAML parser like js-yaml with schema: FAILSAFE_SCHEMA.

Impact

  • Who is affected: All users opening project files with YAML frontmatter
  • Severity: HIGH - Could freeze the application, consume all memory
  • Attack vector: Malicious .prg files, pasted content, imported projects

Environment

  • Version: v3.02+ (current)
  • OS: All platforms

Additional Context

This attack is especially effective because:

  1. Project files are user-controllable
  2. No rate limiting on file operations
  3. Could be used for UI-based DoS attacks

Consider adding:

  • Parse timeouts
  • Memory usage monitoring
  • Warning dialogs for large files

Positively — happy to submit a PR if this is welcome.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions