Stripping SynthID in two steps
2026.09
SynthID is Google and OpenAI's answer to "is this image AI-generated." It embeds a statistical watermark across the pixels at generation time, and their verifier reads it back even after JPEG compression, moderate cropping, and casual editing. The watermark's whole value proposition is surviving the transformations a real user would apply.
Desynth is a two-stage pipeline that removes it and keeps the picture. PSNR 32.47 dB and SSIM 0.956 against the original on OpenAI's GPT Image 2.0 output, SynthID verdict "not found." A prior public bypass on Google's Gemini output scored PSNR 20.21 and SSIM 0.624 on the same kind of test and downsampled the image in the process; this one holds PSNR 28.75 and SSIM 0.946 at native resolution.
Positioning up front: this exists for research and authorized evaluation, and the reason to build it in public is the same reason to build any bypass in public. A watermark that a research script defeats does not survive a determined bad actor either, and the sooner that is measured the sooner the next iteration of the watermark can be honest about what it protects.
Why one pass is not enough
The obvious attack on any image watermark is to run the image back through a diffusion model: encode it into latent space, add noise, denoise. The watermark's statistical signature comes apart in latent space and does not reassemble. Existing public bypasses do exactly this, and the metrics show the cost. A img2img pass at the strength needed to erase the watermark also erases fine detail, so the output reads as smoother, softer, and slightly different from the input everywhere.
The trade is between watermark removal and fidelity, and single-pass approaches sit on the Pareto front where you pick one.
Two stages
Desynth splits the job across two operations, each doing what the other cannot.
Stage 1: minimum-effective denoise. Qwen-Image (GGUF Q4 quantization, ~13 GB) plus a 4-step Lightning distillation LoRA. Denoise strength 0.25, 2 Lightning steps. The goal is to break the watermark's statistical structure with the smallest possible modification to the image. The output at this stage looks like the input with a soft filter over it. Watermark gone, sharpness gone with it.
Stage 2: frequency-domain restore. Split both the stage-1 output and the original image into low- and high-frequency bands with a Gaussian at sigma 1.95. Keep the low band from the clean output and the high band from the original.
final = gaussian(clean, sigma=1.95) + (original - gaussian(original, sigma=1.95))
The low band carries the watermark, so the verifier reads its clean version. The high band carries edges, texture, and fine detail, and it survived the original untouched. Combining them puts the watermark structure permanently below the sigma-1.95 cutoff and returns the perceptual detail above it.
Everything else is knobs.
Numbers
Two comparisons, both against the input image via compare.py:
Against a prior public bypass, Gemini output at 2752x1536:
| metric | desynth | prior work |
|---|---|---|
| PSNR | 28.75 dB | 20.21 dB |
| SSIM | 0.946 | 0.624 |
| SSIM low-frequency | 0.944 | 0.812 |
| SSIM high-frequency | 0.987 | 0.641 |
| MAE (lower is better) | 5.33 | 12.18 |
| output resolution | 2752x1536 | 1501x835 |
| SynthID verdict | not found | not found |
Both remove the watermark. Desynth does so with roughly half the pixel-level error, better structural similarity in both bands, and no downsampling.
Native test, GPT Image 2.0 output at 1460x1078:
| metric | Gaussian (default) | edge mode |
|---|---|---|
| PSNR | 32.47 dB | 31.47 dB |
| SSIM | 0.956 | 0.948 |
| SSIM low-frequency | 0.959 | 0.955 |
| SSIM high-frequency | 0.991 | 0.984 |
| MAE | 3.82 | 4.08 |
| SynthID verdict | not found | not found |
The high-frequency SSIM of 0.991 is the number that matters for perceived quality, since the high band is where a viewer reads detail loss. It sits close enough to the theoretical ceiling of 1.0 that the restore step is doing essentially all of its job.
Edge mode trades a small amount of measurable detail for better shape continuity at contours. The Gaussian split is content-agnostic, so it can bleed a low-band artifact across a sharp edge that the eye reads as a halo. Edge mode uses an edge-aware filter for the split, at the cost of about one dB.
The unsharp knob
--unsharp 0.2 after the restore is the perceptual sweet spot on tested outputs. It does not move the objective metrics much, since it edits the high band the restore already handed you back from the original, but it compensates for the very slight softening the Gaussian split introduces at the sigma boundary. Zero is the safe default; try 0.2 if the output still reads as slightly soft to the eye.
Why the residuals are what they are
The Lightning 4-step distillation is the source of most of what does not survive. Lightning trades sampling quality for speed, so the stage-1 latent is a slightly worse reconstruction of the input than a full 20+ step sampler would produce. That noise ends up in the low band and therefore in the final output. Dropping Lightning for proper sampling would tighten the numbers further at roughly 5x the runtime.
Quantization matters less than expected. Q4_K_M is small enough to run on 8 GB VRAM (with sequential CPU offload below 12 GB), and the metrics above are on the Q4 path. Higher-precision transformers are worth a run if the residual matters more than throughput.
What this says about SynthID
The watermark is a low-frequency signal by construction. It has to be, because high-frequency signals do not survive JPEG. The design choice that makes SynthID robust to compression is the same choice that makes it vulnerable to a two-stage pipeline that treats the low and high bands independently. Any watermark whose survival requires the low band is defeated by replacing the low band with a clean version of it.
The mitigation is not obvious. Pushing the watermark into the high band trades robustness for covertness; making it span both bands makes it easier to detect and easier to strip. The useful research direction is probably watermarks that live in learned latent features rather than in pixel-frequency bands, so the stripping step has to reconstruct a semantically correct image rather than just recombine two spectra. That is a strictly harder attack, but it is not the attack this pipeline runs.
Running it
python desynth.py # processes original.png
python desynth.py path\to\image.png # any input
python compare.py Original.png out\<output>.png
Output lands at out/<name>_desynth_s8_d0.250_p1_r1.95.png. First run pulls ~250 MB of VAE plus configs from Hugging Face and caches them. Tested on a 5060 Ti 8 GB with 32 GB system RAM; sequential CPU offload kicks in below 12 GB VRAM automatically.
Baseline workflow and the watermark hypothesis are from 00quebec/Synthid-Bypass. This pipeline reimplements the core idea in plain Python without ComfyUI, ControlNet, or the face-detail path, and replaces the heavier redraw with the two-step minimum denoise plus frequency-domain restore described above.
Research and authorized-evaluation use only.