Skip to content

security(ci): verify WOFF and WOFF2 magic bytes for committed font as… - #500

Closed
seuninfoo-svg wants to merge 1 commit into
Sub-Rosa-Issue:mainfrom
seuninfoo-svg:verify_WOFF
Closed

seuninfoo-svg wants to merge 1 commit into
Sub-Rosa-Issue:mainfrom
seuninfoo-svg:verify_WOFF

Conversation

@seuninfoo-svg

Copy link
Copy Markdown

Close #478

PR: WOFF/WOFF2 Magic Bytes Verification for Committed Font Assets

Summary

Add a static repository check for committed font assets. Files named .woff or .woff2 can be used to conceal JavaScript or other malicious content. Real font files have recognizable binary signatures (magic bytes) that can be checked without executing them.

Problem

  • Files with .woff or .woff2 extensions can disguise executable content
  • No automated verification that committed font files are actually valid fonts
  • Supply-chain risk: malicious fonts could execute when served to browsers

Solution

Created scripts/check-font-magic-bytes.mjs — a static binary validator that:

  1. Scans repository for .woff and .woff2 files (excludes fixtures/ and node_modules/)
  2. Reads only the first 4 bytes of each file
  3. Verifies magic bytes:
    • .woff2 → wOF2 (hex: 77 4f 46 32)
    • .woff → wOFF (hex: 77 4f 46 46)
  4. Reports only invalid paths, exits non-zero on failure
  5. Never executes files — reads bytes only

Files Added

scripts/check-font-magic-bytes.mjs         # Main checker (executable + exportable)
scripts/check-font-magic-bytes.test.mjs    # 8 tests
fixtures/font-magic-bytes/
  ├── valid.woff2                          # Valid WOFF2 (wOF2 magic)
  ├── valid.woff                           # Valid WOFF (wOFF magic)
  ├── fake.woff2                           # Text disguised as WOFF2
  └── fake.woff                            # Text disguised as WOFF

Files Modified

  • package.json — Added font:check and font:test scripts

Usage

# Check all committed font files (excludes fixtures/)
pnpm font:check

# Run test suite
pnpm font:test

# Check specific file or directory
node scripts/check-font-magic-bytes.mjs path/to/font.woff2
node scripts/check-font-magic-bytes.mjs path/to/fonts/

Example Output

Clean Repository

$ pnpm font:check
{"timestamp":"...","level":"info","event":"ok","message":"OK  no font files found"}

Invalid Font

$ node scripts/check-font-magic-bytes.mjs fixtures/font-magic-bytes/fake.woff
{"timestamp":"...","level":"error","event":"fail","message":"fixtures/font-magic-bytes/fake.woff: invalid WOFF magic bytes (expected 774f4646, got 54686973)"}

Test Coverage

Test Description
passes for valid WOFF2 fixture wOF2 magic bytes accepted
passes for valid WOFF fixture wOFF magic bytes accepted
fails for text-disguised-as-WOFF Plain text .woff rejected
fails for text-disguised-as-WOFF2 Plain text .woff2 rejected
passes when no font files Empty directory OK
reports only the invalid path Valid files not reported on mixed dir
exits non-zero on failure CI-friendly exit codes
reads bytes only Never executes files

Integration

Runs in CI to verify committed font assets:

- name: Verify font magic bytes
  run: pnpm font:check

Design Decisions

  • Excludes fixtures/ and node_modules/ — Test fixtures and dependencies not checked by default
  • Reads exactly 4 bytes — Minimal I/O, no full file reads
  • Accepts file or directory args — Flexible for CI and local use
  • No external dependencies — Pure Node.js fs module
  • Logging via existing @sub-rosa/logging — Consistent JSON diagnostics

Acceptance Criteria ✅

  • .woff2 files must begin with wOF2 magic bytes
  • .woff files must begin with wOFF magic bytes
  • Tests cover one valid and one text-disguised-as-font fixture each
  • CI reports only the invalid path and exits non-zero
  • Add a root package script for local use (font:check, font:test)
  • The checker must read bytes only and never execute a file

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

security(ci): verify WOFF and WOFF2 magic bytes for committed font assets

2 participants