From f91f9fd9fcb3874d36b08be25e1183fe8633ef1a Mon Sep 17 00:00:00 2001 From: Victor Kuznetsov Date: Thu, 27 Aug 2026 11:21:08 -0700 Subject: [PATCH] Record the public Microsoft Content Provenance check URL The InvisMark strength ladder was measured against Microsoft's public Content Provenance page, but no doc or comment carried its URL - the API how-to link was the only address recorded anywhere, and the page is what a human can actually check without an Azure account. Record https://ai.azure.com/nextgen/validate in supported-signals.md, the watermarking landscape, and the strength derivation comment, with the honest caveat that its collapsed verdict tops out at Inconclusive rather than the API's separate watermark-negative result. --- docs/supported-signals.md | 6 +++++- docs/watermarking-landscape.md | 2 +- src/remove_ai_watermarks/_internal/watermark_profiles.py | 5 +++-- 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/docs/supported-signals.md b/docs/supported-signals.md index 4902414..9a9134a 100644 --- a/docs/supported-signals.md +++ b/docs/supported-signals.md @@ -152,7 +152,11 @@ inspection cannot independently verify the output. Microsoft's official [Content Provenance Detection API](https://learn.microsoft.com/en-us/azure/ai-services/content-safety/how-to/how-to-provenance-detection) is the external oracle: it reports pixel `Watermark` and embedded `C2PA` results separately; a control-positive, output-negative pair is the available per-file -verification path. +verification path. The API needs Azure credentials; the page a human can check +without an account is . Its verdict is +weaker than the API's: it collapses watermark and C2PA into one rendered result +and tops out at `Inconclusive` rather than a watermark-negative, so treat +`Inconclusive` on a processed file as "not confirmed", not as "detected still". Meta Muse Image stamps every output with Content Seal, a proprietary invisible pixel watermark, and ships no visible mark (the legacy `Imagined with AI` diff --git a/docs/watermarking-landscape.md b/docs/watermarking-landscape.md index 8147616..36703ef 100644 --- a/docs/watermarking-landscape.md +++ b/docs/watermarking-landscape.md @@ -66,7 +66,7 @@ payloads. Removal remuxes either container through ffmpeg with stream copy. encoder and the carrier remains decodable. - **Invisible but NOT locally detectable (proprietary, API/oracle only — same wall as SynthID):** Amazon Titan Image Generator + Nova Canvas (Bedrock `DetectGeneratedContent` API), Kakao (new SynthID image adopter, May 2026), NVIDIA Cosmos (SynthID video). No local detector possible; treat like SynthID. - **C2PA 2.4 "Durable Content Credentials" (April 2026; verified against the spec) raise the bar for metadata stripping.** 2.4 defines soft bindings (an invisible watermark or a content fingerprint) plus a server-side manifest repository and a new `c2pa.repository-receipt` assertion. Per the spec: "if a C2PA manifest is removed from an asset, but a copy of that manifest remains in a provenance store elsewhere, the manifest and asset may be matched using available soft bindings." So our local `metadata --remove` deletes the *embedded* manifest, but a fingerprint/watermark soft binding can still re-link the image to its manifest in a repository server-side. Stripping the file is becoming necessary-but-not-sufficient against durable provenance. (Our parsers target the stable embedded-manifest format documented in C2PA 2.1 §11; that format is unchanged in 2.4 -- the new pieces are repository/soft-binding infra, not the on-file box layout, so no parser change is implied.) Spec: https://spec.c2pa.org/specifications/specifications/2.4/specs/C2PA_Specification.html We now READ the soft-binding `alg` (`C2PA_SOFT_BINDINGS` / `soft_binding_vendors_in`) to name the forensic-watermark vendor, preserve the structured assertion's signed `value`, and locally DECODE the one open scheme, Adobe TrustMark (`trustmark_detector`); the rest stay name-only unless a compatible decoder is independently verified. -- **Microsoft Paint and Photos InvisMark (reverse-engineered 2026-08-20):** Paint receives a per-generation GUID from remote prompt moderation, embeds it into locally generated pixels, and records the same value in `c2pa.soft-binding` under `com.microsoft.invismark.1`. The C2PA soft-binding registry independently identifies that algorithm as Microsoft Responsible AI InvisMark for image and video. Paint's 144-bit writer framing does not match the public repository's 100-bit pretrained checkpoint interface, so compatibility is not assumed. The parser reports the signed identifier; there is no validated local pixel decoder. Microsoft's external Content Provenance Detection API is the removal oracle because it reports `Watermark` separately from `C2PA`; a metadata-stripped, pixel-identical control must remain watermark-positive before an output-negative result is attributed to pixel removal. Sources: https://xusheng.dev/posts/reversing/mspaint_invisible_watermark/main/, https://github.com/c2pa-org/softbinding-algorithm-list/blob/main/softbinding-algorithm-list.json, and https://learn.microsoft.com/en-us/azure/ai-services/content-safety/how-to/how-to-provenance-detection +- **Microsoft Paint and Photos InvisMark (reverse-engineered 2026-08-20):** Paint receives a per-generation GUID from remote prompt moderation, embeds it into locally generated pixels, and records the same value in `c2pa.soft-binding` under `com.microsoft.invismark.1`. The C2PA soft-binding registry independently identifies that algorithm as Microsoft Responsible AI InvisMark for image and video. Paint's 144-bit writer framing does not match the public repository's 100-bit pretrained checkpoint interface, so compatibility is not assumed. The parser reports the signed identifier; there is no validated local pixel decoder. Microsoft's external Content Provenance Detection API is the removal oracle because it reports `Watermark` separately from `C2PA`; a metadata-stripped, pixel-identical control must remain watermark-positive before an output-negative result is attributed to pixel removal. The no-account web page for the same check is (its `Inconclusive` verdict is weaker than the API's separate watermark result). Sources: https://xusheng.dev/posts/reversing/mspaint_invisible_watermark/main/, https://github.com/c2pa-org/softbinding-algorithm-list/blob/main/softbinding-algorithm-list.json, and https://learn.microsoft.com/en-us/azure/ai-services/content-safety/how-to/how-to-provenance-detection - **Built in the dated batch:** soft-binding vendor detection, IPTC Photo Metadata AI-disclosure fields, C2PA detection and stripping for supported ISOBMFF video, the optional Adobe TrustMark decoder, and temporally stabilized diff --git a/src/remove_ai_watermarks/_internal/watermark_profiles.py b/src/remove_ai_watermarks/_internal/watermark_profiles.py index aacf459..c27bf2d 100644 --- a/src/remove_ai_watermarks/_internal/watermark_profiles.py +++ b/src/remove_ai_watermarks/_internal/watermark_profiles.py @@ -79,8 +79,9 @@ QWEN_ZIMAGE_GOOGLE_STRENGTH = 0.27 # cross-source spread (0.00725) to the worst clean boundary: 0.0695 + 0.00725. QWEN_ZIMAGE_OPENAI_STRENGTH = 0.07675 -# Microsoft's public detector returned Inconclusive rather than an API-level -# watermark-negative verdict. Three valid Paint sources first cleared at 0.04125, +# Microsoft's public detector (https://ai.azure.com/nextgen/validate) returned +# Inconclusive rather than an API-level watermark-negative verdict. Three valid +# Paint sources first cleared at 0.04125, # 0.055, and 0.095. Add one full observed cross-source spread to the worst clean # boundary: 0.095 + (0.095 - 0.04125) = 0.14875, rounded up to 0.15. This is a # measured corpus margin, not a universal InvisMark threshold.