Files
ginxsom/src/metadata_scan.h
T
Laan Tungir 694219d003 Phase 1: server-side metadata detect-and-reject backstop
Add metadata_scan.c/.h: pure-C, dependency-free byte scanners for JPEG
(APP1 Exif/XMP, APP13 IPTC), PNG (eXIf, denylisted tEXt/iTXt/zTXt keys),
WebP (EXIF/XMP chunks), GIF (comment/XMP extensions), PDF (/Author,
/Producer, /CreationDate, etc.), TIFF (ExifIFD/GPS IFD pointers), HEIC
(Exif item payload). Conservative — when in doubt, flags.

Wire into handle_upload_request_with_validation() after SHA-256 compute,
before fopen: rejects with 415 + X-Reason: exif_detected, preserving
BUD-01 content addressing (server never rewrites). Add metadata_scan_enabled
config toggle (default true). Add to Makefile + Dockerfile.alpine-musl.

Tests: metadata_scan_test.c unit test (20 cases) + metadata_scan_test.sh
integration test (7 cases, run against live server).

See ~/lt/metadata_stripping/plans/blob-metadata-stripping.md (Part 2).
2026-07-31 07:26:07 -04:00

66 lines
2.1 KiB
C

/*
* metadata_scan.h — Privacy-metadata detection for uploaded blobs.
*
* The server-side backstop of the metadata-stripping pipeline. Scans the
* in-memory upload buffer for EXIF / XMP / IPTC / PNG text chunks / PDF
* author tags / GIF comments / HEIC Exif items and rejects the upload if
* forbidden metadata is present.
*
* The scanner is conservative: when in doubt, flag. The cost of a false
* positive is a client retry with stripped bytes; the cost of a false
* negative is a privacy leak.
*
* See ~/lt/metadata_stripping/plans/blob-metadata-stripping.md (Part 2).
*/
#ifndef METADATA_SCAN_H
#define METADATA_SCAN_H
#include <stddef.h>
#ifdef __cplusplus
extern "C" {
#endif
typedef enum {
META_SCAN_OK = 0,
META_SCAN_FORBIDDEN_FOUND = 1,
META_SCAN_ERROR = 2
} meta_scan_result_t;
/*
* Scan an in-memory blob for privacy-sensitive metadata.
*
* data — pointer to the uploaded bytes
* size — number of bytes
* content_type — MIME type from the Content-Type header (may be NULL)
* reason_out — buffer to receive a short human-readable reason string
* (e.g. "exif_detected: JPEG APP1 Exif segment")
* reason_out_size — size of reason_out; the reason is truncated to fit
*
* Returns:
* META_SCAN_OK — no forbidden metadata found
* META_SCAN_FORBIDDEN_FOUND — forbidden metadata detected; reason_out filled
* META_SCAN_ERROR — internal error (scan skipped)
*
* The format is auto-detected from the byte signature; content_type is used
* only as a hint (e.g. to distinguish a mislabeled TIFF).
*/
meta_scan_result_t metadata_scan(const unsigned char *data,
size_t size,
const char *content_type,
char *reason_out,
size_t reason_out_size);
/*
* Read the metadata_scan_enabled config row. Returns 1 if the server should
* reject uploads carrying forbidden metadata (default), 0 if disabled.
*/
int metadata_scan_enabled(void);
#ifdef __cplusplus
}
#endif
#endif /* METADATA_SCAN_H */