So Anthropic finally did it. They’ve been teasing this whole “AI content detection” thing for a while, making it sound like they built something that could identify AI-generated content from word choice and writing patterns. People on my Twitter feed are losing their minds over it, talking about canceling their subscriptions and all that.
And I’m sitting here thinking, let me just look at what they actually shipped.
I went ahead and asked Claude to generate me a png that contains “Hello World” text, because nothing else comes to a programmer’s mind except hello world.
Then I made a copy of it and renamed the png to .txt like a caveman, just to see if there were some strings like “Anthropic” hiding inside to understand how the mechanism works.
After I opened the txt, I didn’t even need to scroll. It’s directly looking at me: “Anthropic Claude Content Signing”.

So I looked up what this thing is called. Anthropic has a check content page where they check if a file was made by Claude using something called C2PA. They check our metadata, so I figured I’d check theirs. Reverse uno card.
In the txt file I found this string: Claude.aigversione1.0.0worg.contentauth.c2pa_rsf0.90.0. That tells us they’re using a Rust crate called c2pa-rs version 0.90.0 to generate the signature. So I went to the GitHub repo and looked at how it actually works. In the README I found these lines:
- JPEG: Wraps into multi-segment APP11 data with JPEG XT headers
- JPEG XL: Wraps into a single ISOBMFF jumb superbox containing the C2PA manifest store
- PNG: Wraps into a caBX chunk with CRC
So pngs have chunks just like .exe files? I never heard about this to be honest. So I wrote a simple python script to see if that’s the chunk that’s betraying our school projects:
import struct
with open("hello_world_text.png", "rb") as f:
f.read(8)
while chunk := f.read(8):
length, type = struct.unpack(">I4s", chunk)
data = f.read(length)
crc = f.read(4)
if type.decode() == "caBX":
print(type.decode(), length, data)

There it is. Now we just need to write the same png to a new file without including that chunk.
import struct
with open("hello_world_text.png", "rb") as f:
sig = f.read(8)
chunks = []
while chunk := f.read(8):
length, type = struct.unpack(">I4s", chunk)
data = f.read(length)
crc = f.read(4)
if type.decode() != "caBX":
chunks.append(chunk + data + crc)
with open("clean.png", "wb") as f:
f.write(sig)
for c in chunks:
f.write(c)
Then I verified both images on Anthropic’s own check content page:


So yeah, before you start thinking this is some next-level technology that analyzes writing patterns and detects everything Claude has ever touched, maybe it’s just a signature slapped onto the file. Don’t be lazy to research and improve yourselves, my friends.
That said, turns out Anthropic actually is building text watermarking that works at the token level by biasing word choices during generation. That’s the real deal and way more interesting than a metadata chunk. That’s probably why their check content page only supports media files (JPG, PNG, GIF, WEBP, MP4, etc.) and not .txt or any coding extensions, the text watermarking isn’t fully public yet. When it is though, maybe we’ll get to crack that next.
And if there’s already some tool out there that does this, I honestly don’t care. I enjoyed doing this project and when I tried the obvious stuff like exiftool -all= it didn’t work anyway, so here we are.
I also made a small cli tool just for png files if you want to use it: claude-png-unsign. Other formats like jpeg and jxl store C2PA data differently so I didn’t bother, but PRs are open if anyone wants to add support.
Hope to see you guys in the next blogs.