Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 38 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
name: CI

on:
push:
branches: [main]
pull_request:
branches: [main]

permissions:
contents: read

jobs:
validate:
runs-on: ubuntu-latest
steps:
- name: Check out repository
uses: actions/checkout@v4

- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: 24
cache: npm

- name: Install dependencies
run: npm ci

- name: Lint
run: npm run lint

- name: Type-check
run: npm run typecheck

- name: Test
run: npm test

- name: Build
run: npm run build
6 changes: 6 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
node_modules/
dist/
coverage/
*.log
.DS_Store

5 changes: 5 additions & 0 deletions .prettierignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
dist/
coverage/
node_modules/
package-lock.json

3 changes: 3 additions & 0 deletions .prettierrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"proseWrap": "preserve"
}
10 changes: 10 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# Changelog

All notable changes will be documented here. The project intends to follow semantic versioning once releases begin.

## Unreleased

- Repository foundation.
- TypeScript library scaffold.
- Public API skeleton.
- Security and architecture documentation.
21 changes: 21 additions & 0 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
MIT License

Copyright (c) 2026 Secure Tools Project contributors

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
43 changes: 43 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# secure-metadata

`secure-metadata` is a pre-release TypeScript library for deterministic, security-conscious inspection, cleaning, and verification of metadata in binary image formats. It is being built for privacy-first, entirely local use with no analytics, telemetry, network access, runtime CDN, or pixel decoding.

> **Development status:** Sprint 0 establishes the repository and API foundation. JPEG, PNG, WebP, EXIF, TIFF, XMP, IPTC, and ICC parsing and all cleaning behavior are not implemented yet.

## Format status

JPEG, WebP, and PNG are planned, in that order. See [format support](docs/format-support.md) for the intended progression.

## Installation

The package is not published. Installation instructions will be added for the first pre-release.

## Public API

The future top-level API is deliberately small:

```ts
import {
cleanMetadata,
inspectMetadata,
verifyMetadata,
} from "secure-metadata";
```

All three functions currently throw a typed `NotImplementedError`. Public binary inputs are `Uint8Array | ArrayBuffer`; Node.js `Buffer` values work structurally as `Uint8Array` but are not part of the public contract.

## Security philosophy

Every byte is untrusted. Future binary reads will use bounded primitives, traversal will have hard limits, and malformed input must not crash a parser. Cleaning will preserve unknown structures and ICC/color information by default, and cleaner output will be independently inspectable. See the [security model](docs/security-model.md), [architecture](docs/architecture.md), and [cleaning policy](docs/cleaning-policy.md).

## Non-goals

The library does not perform image decoding or encoding, visual redaction, pixel-content privacy analysis, steganography detection, or malware scanning. Absence of metadata is never proof that an image contains no private information.

## Secure Tools ecosystem

This is an independent open-source library in the broader Secure Tools ecosystem. It has its own package, lifecycle, and repository; future Secure Tools integration will use a pinned browser artifact rather than coupling application code to this repository.

## License

MIT. See [LICENSE](LICENSE).
17 changes: 17 additions & 0 deletions SECURITY.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# Security Policy

## Supported versions

`secure-metadata` is pre-release software and currently has no supported release line. A supported-version table will be added before the first public release.

## Reporting a vulnerability

Binary parser vulnerabilities should be coordinated privately before public disclosure. If GitHub private vulnerability reporting is enabled for this repository, use **Security → Report a vulnerability**. Do not include a malicious sample or parser details in a public issue.

If private vulnerability reporting is not available, there is not yet a dedicated reporting channel. Maintainers must configure one before the first public release; do not invent or guess a contact address.

Please include the affected revision, impact, reproduction steps, and the smallest safe test case you can provide. Parser crashes, incorrect or out-of-bounds-style offset logic, unbounded traversal or allocation, and resource exhaustion are security-relevant.

## Threat model

All input bytes are treated as malicious. The library is designed to inspect container and metadata structures without decoding pixels, touching the filesystem, or using the network. Hard limits and bounded reads are core defenses, while cleaner output must be independently parsed and verified.
36 changes: 36 additions & 0 deletions docs/architecture.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# Architecture

`secure-metadata` is organized as a side-effect-free binary library. Its planned data flow is:

```text
Input bytes
Format detection
Container parser
Metadata decoder
Metadata normalization/classification
Inspector / policy engine
Cleaner
Output bytes
Re-inspection / verification
```

## Layer boundaries

- **Container parsing** identifies and bounds JPEG segments, PNG chunks, or WebP RIFF chunks without decoding pixels.
- **Metadata decoding** interprets known metadata payloads. EXIF/TIFF will be one shared decoder reused by JPEG, PNG, and WebP.
- **Normalization and classification** maps format-specific fields to stable namespaces and semantic categories.
- **Privacy relevance** is an independent description of whether an entry can concern privacy. It is not a contextual risk score.
- **Cleaning policy** decides which proven structures to remove while preserving required, color, rendering, image-payload, and unknown data by default.
- **Verification** independently re-inspects cleaner output and compares it with an explicit expectation.

Format packages will depend on bounded primitives in `src/core/binary`. Decoders and policy code must not perform ad hoc binary reads. Public APIs accept bytes and return values without filesystem, network, browser-global, or other environmental side effects.

Sprint 0 establishes interfaces and boundaries only. Format detection, binary primitives, parsers, decoders, cleaning, and verification logic are intentionally not implemented.
15 changes: 15 additions & 0 deletions docs/cleaning-policy.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# Cleaning Policy Direction

Cleaning is not implemented in Sprint 0. This document records the intended conservative policy for future work.

An initial privacy-clean mode should remove EXIF, GPS, XMP, IPTC, comments, and privacy-relevant textual metadata. It should preserve the encoded image payload, required container structures, ICC and other color profiles, rendering-critical metadata, and unknown structures unless the relevant format specification proves removal is safe.

For v0.1, whole EXIF containers are preferred over selective TIFF rewriting:

```text
JPEG APP1 EXIF → remove whole EXIF APP1
PNG eXIf → remove whole eXIf chunk
WebP EXIF → remove whole EXIF chunk
```

Selective EXIF field rewriting is postponed. This reduces offset-rewrite complexity and makes cleaner behavior easier to audit. Unaffected bytes should remain byte-for-byte identical whenever the container format permits it, and output must be re-inspected rather than trusted merely because a write completed.
21 changes: 21 additions & 0 deletions docs/format-support.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# Format Support

No image format is parsed in Sprint 0. Planned implementation priority is:

1. JPEG
2. WebP
3. PNG

## JPEG

JPEG is first because its segment model provides the initial foundation for marker parsing and bounded traversal. Future work covers APP segments, EXIF, shared TIFF IFD and GPS decoding, XMP, IPTC, comments, and the distinction between privacy metadata and ICC profiles.

## WebP

WebP support will add bounded RIFF chunk parsing, EXIF, XMP, ICCP, image and animation payload distinctions, and consistent handling of VP8X feature flags when metadata chunks change.

## PNG

PNG support will add chunk parsing, textual metadata, eXIf, XMP, ICC and color chunks, privacy-relevant ancillary chunks, and detection of compressed metadata. Compressed metadata decompression is not part of Sprint 0.

Format claims will track implemented and tested behavior; planned items are not advertised as supported.
30 changes: 30 additions & 0 deletions docs/security-model.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# Security Model

Binary metadata parsing processes attacker-controlled structure, sizes, offsets, encodings, and nesting. The project therefore treats malformed files, parser panics, excessive allocation or traversal, and incorrect offset arithmetic as security concerns.

## Invariants

1. All binary input is untrusted.
2. All binary reads must eventually go through bounded primitives.
3. No parser may perform unchecked offset arithmetic.
4. Parser traversal must be hard bounded.
5. TIFF/IFD traversal must eventually include cycle detection.
6. Core functions must not make network requests.
7. Core functions must not access the filesystem.
8. The library must not decode image pixel payloads.
9. Unknown metadata must not be deleted by inference.
10. Privacy cleaning must preserve ICC and color data by default unless explicitly requested otherwise.
11. Cleaning should preserve unaffected bytes byte-for-byte whenever practical.
12. Cleaner output must be independently inspectable and verifiable.
13. The library must never claim that an image contains no private information merely because metadata is absent.
14. Steganography detection, malware scanning, visual redaction, and pixel-content privacy analysis are outside project scope.

## Hard limits

Default limits bound input size, container counts, metadata entries, TIFF depth and entry counts, strings, future decompressed data, and diagnostics. The defaults are exported as `DEFAULT_PARSE_LIMITS`. They are conservative operational safeguards, not permanent API guarantees, and may evolve during `0.x` development.

Limits complement bounds checks; they do not replace them. Future parsers must fail safely or produce bounded diagnostics rather than crash on malformed input.

## Environment and dependencies

Core code is local-only and side-effect-free. It has no network, analytics, telemetry, filesystem, DOM, or pixel-codec behavior. The package starts with zero runtime dependencies. Development tools are not part of the shipped runtime.
25 changes: 25 additions & 0 deletions eslint.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import eslint from "@eslint/js";
import tseslint from "typescript-eslint";

export default tseslint.config(
{
ignores: ["coverage/**", "dist/**", "node_modules/**"],
},
{
files: ["**/*.ts"],
extends: [eslint.configs.recommended, ...tseslint.configs.strict],
languageOptions: {
parserOptions: {
projectService: true,
tsconfigRootDir: import.meta.dirname,
},
},
rules: {
"@typescript-eslint/consistent-type-exports": "error",
"@typescript-eslint/consistent-type-imports": [
"error",
{ fixStyle: "inline-type-imports" },
],
},
},
);
3 changes: 3 additions & 0 deletions fixtures/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Fixtures

Future generated fixtures should be reproducible and documented. Real-world fixtures must have a clear redistribution license and provenance, must not contain unintended personal information, and must be reviewed before commit. Sprint 0 intentionally contains no binary fixtures.
Loading
Loading