{"slug": "ms-paint-and-photos-inivisibly-watermark-even-locally-generated-output-with-guid", "title": "MS Paint and Photos inivisibly watermark even locally generated output with GUID", "summary": "Microsoft Paint and Photos embed server-issued GUIDs as invisible watermarks in locally generated images, according to a reverse-engineering analysis by security researcher xusheng.dev. The apps send prompts to a remote server for moderation, which returns a GUID that is embedded into the image, separate from the visible watermark setting. On Copilot+ PCs, image generation is local but prompt moderation remains remote, and Microsoft discloses that Paint adds C2PA metadata to AI-generated images, limiting saves to PNG, JPEG, GIF, and .paint formats.", "body_md": "14 minutes\n\n#\n[Microsoft Paint and Photos Embed Server-Issued GUIDs as Invisible Watermarks in Locally-Generated Images](https://xusheng.dev/posts/reversing/mspaint_invisible_watermark/main/)\n\n## TL;DR\n\n- Microsoft Paint supports both local and cloud image generation\n- Paint and Photos also ship local AI models\n- The two apps send the prompt to a remote server for moderation\n- The server returns a GUID along with the moderated prompt\n- The GUID is embedded into the locally generated image as an invisible watermark\n- A separate visible-watermark setting does not control this invisible watermark\n- On Copilot+ PCs, image generation is local but prompt moderation remains remote\n- Microsoft discloses that Paint adds C2PA metadata to AI-generated images\n- AI-generated image saves limited to C2PA-preserving formats: PNG, JPEG, GIF, and\n`.paint`\n\n## A curious look at Microsoft Paint\n\nThis research started with my curiosity about Paint. I recently had some success looking into less-explored Windows features like [UCPD](https://binary.ninja/2026/08/04/ucpd-dynamic-rules.html), [WHESCVC](https://xusheng.dev/posts/reversing/whesvc/main/), and I have long known that Microsoft\nadded a bunch of [AI features](https://support.microsoft.com/en-us/windows/ai/ai-apps/use-copilot-pc-features-in-paint) into the Paint app.\nI do not know if anyone actually uses Paint + AI to generate images, but I wanted to see how exactly the image generation works.\n\nBefore I started, I expected that it simply called a remote API to do the image generation. However, after I set up [Binary Ninja MCP](https://dev-docs.binary.ninja/guide/mcp.html) with Codex and started the analysis, I soon realized that Microsoft actually shipped local models in Windows as part of Copilot.\n\nThe Paint App is sitting in the following path (yes, they are all [Windows Apps](https://learn.microsoft.com/en-us/windows-app/overview) now):\n\n```\nC:\\Program Files\\WindowsApps\\Microsoft.Paint_11.2605.71.0_x64__8wekyb3d8bbwe\\PaintApp\\\n```\n\nAnd there are four apparent model files with the `.onnxe`\n\nextension:\n\n```\nseg.onnxe          23.1 MB\ninseg_enc.onnxe    28.0 MB\ninseg_dec.onnxe    16.5 MB\nmager.onnxe       302.4 MB\n```\n\nThe format of `seg.onnxe`\n\nwas [previously known](https://itstechbased.com/new-windows-11-build-25947-new-23h2-news-new-paint-and-microsoft-store-and-fixes-canary/), i.e., when it is XORed with the string `Microsoft_2023`\n\n, it becomes a normal ONNX file. However, the format of the other three `.onnxe`\n\nfiles initially looked different.\n\nIt turned out that Microsoft had not changed the algorithm, only the key. `segapi.dll`\n\ncontains a small key registry:\n\n``` php\nps_enc_key.1.0.80-main -> \"Microsoft_2023\"\nps_enc_key.1.0.81-main -> a 4,096-byte alphanumeric string\n```\n\nAfter decryption, `onnx.checker.check_model()`\n\nworks on all of them:\n\n| Model | Graph |\n|---|---|\n`seg.onnx` |\n1,094 nodes, input `input_image` , output `output` |\n`inseg_enc.onnx` |\n1,014 nodes, output `image_embeddings` |\n`inseg_dec.onnx` |\n1,133 nodes, inputs for embeddings, points and masks; output `masks` |\n`mager.onnx` |\n15,284 nodes, image/mask inputs; output `output` |\n\n## A visible watermark\n\nWhile walking through these files, I found a `Watermarker.dll`\n\n:\n\nThis is not super surprising to me, because while I interacted with the Paint app, I already discovered that it has a setting to embed a [visible watermark](https://support.microsoft.com/en-us/topic/include-a-watermark-when-content-from-microsoft-365-is-ai-generated-b00a656e-ae61-4692-8086-67d004421030) to the image that it produces:\n\nThe visible watermark is just a small Copilot logo at the bottom right of the image, which is totally normal.\n\nThen, out of nowhere, I decided to ask AI to analyze the DLL and see if it could also be embedding an *invisible* watermark. This is part of my intuition as a reverse engineer, because the file is 1.67 MB in size, which is unusually large for such trivial functionality (arguably, the visible watermark does not even require a separate DLL). Apparently, the recent Claude Code [text-watermark announcement](https://www.anthropic.com/news/claude-text-watermark) also played a role in prompting me to think about this possibility.\n\n## An *invisible* watermark\n\nTo begin with, the visible watermark is added by `AddPerceptibleWatermark`\n\n:\n\n```\nCPBDoc::Save(...)\n  |\n  `-- perceptible-watermark save helper(bitmap, WatermarkSetting)\n        |\n        +-- WatermarkSetting::Never\n        |     `-- return the original bitmap\n        |\n        +-- WatermarkSetting::AskEveryTime\n        |     `-- show the Yes / No confirmation popup\n        |           +-- No: return the original bitmap\n        |           `-- Yes: continue\n        |\n        `-- Always or confirmed Yes\n              +-- Paint::AI::GetPerceptibleWatermarkSvg()\n              `-- Paint::AI::AddPerceptibleWatermark(bitmap, SVG stream)\n                    `-- composite the visible Copilot logo\n```\n\nThen there is also a different `WmkWriteWatermark`\n\nfunction:\n\n```\nWatermarker.dll!WmkWriteWatermark(\n    output_pixels,\n    payload,\n    payload_length,\n    width,\n    height,\n    stride,\n    input_pixels,\n    pixel_format);\n```\n\nTracing the call tree, we can see `WmkWriteWatermark`\n\nis called after a local Stable Diffusion image generation. And if `WmkWriteWatermark`\n\nfails, Paint converts the entire generation into an error rather than returning the image without it:\n\n```\nCocreatorViewModel::GenerateImageAsync(...)\n  |\n  `-- Paint::AI::StableDiffusionHelpers::GenerateAsync(..., watermarkId, ...)\n        |\n        `-- Microsoft.ImageCreation.ImageGenerator\n              |\n              `-- NPU-generated image result\n                    |\n                    +-- output safety/moderation checks\n                    |\n                    +-- Paint::AI::AddWatermark(bitmap, watermarkId)\n                    |     |\n                    |     `-- Watermarker.dll!WmkWriteWatermark(...)\n                    |           |\n                    |           +-- success: return the watermarked bitmap\n                    |           `-- failure: turn generation into an error\n                    |\n                    `-- construct successful StableDiffusionResult\n```\n\nThen it is natural to ask what the incoming `payload`\n\nactually is. It quickly becomes apparent that it must be 16 bytes:\n\n```\nif (payload_length < 16)\n    return -6;\n\nif (payload_length > 16)\n    return -5;\n```\n\nIt is funny to me that the code is using two different error codes when the payload is too short or too long. The function then ignores the length parameter and uses a hard-coded loop bound when it copies the payload:\n\n```\nfor (size_t i = 0; i < 16; i++)\n    message.push_back(payload[i]);\n```\n\nWe do not yet know what the 16-byte payload is, but as we will see later, it is a GUID! `WmkWriteWatermark`\n\ndoes not embed the GUID directly. Its wrapper constructs the following 18-byte (144-bit) message:\n\n```\n0x4c || GUID[0..15] || (sum of the 16 GUID bytes modulo 256)\n```\n\nThe core encoder rounds the usable image dimensions down to multiples of eight and keeps 144 counters, one for each bit. It requires every bit to be placed at least three times.\n\nThe encoder itself can be summarized as:\n\n```\nWmkWriteWatermark(output, guid, 16, width, height, stride, input, format)\n  |\n  +-- validate pointers, format, stride, and payload length\n  +-- require width >= 192 and height >= 192\n  +-- construct payload\n  |     `-- 0x4c || GUID || byte-sum checksum\n  +-- expand 18 bytes into 144 individual bits\n  +-- round usable dimensions down to 8-pixel boundaries\n  +-- scan/select suitable image blocks\n  +-- quantize selected block/matrix values according to each bit\n  +-- require at least three successful placements per bit\n  |     |\n  |     `-- insufficient capacity -> return -8\n  `-- reconstruct RGB pixels into the output buffer\n```\n\nThe embedding loop performs small quantized changes over selected image blocks. It contains 3-by-5 matrix operations and a matrix-decomposition routine, and it uses constants including `24.0`\n\n, `0.25`\n\n, `0.5`\n\n, and `0.2`\n\n. This looks like a content-adaptive block-domain, SVD-style watermark.\n\nI am not an expert in image watermarking, but one thing should be clear – this is an invisible watermark! AI even wrote some code to call this function directly and tested it with a synthetic 512-by-512 BGRA image – 193,376 of the 262,144 pixels changed after adding the watermark.\n\nThat led to the next question. Where does the input of the watermark come from?\n\n## a GUID from remote prompt moderation\n\nAt the `WmkWriteWatermark`\n\nboundary, the payload is only a pointer and a length. Knowing that it must be 16 bytes was a clue, but many things can be 16 bytes. I therefore started walking backward through its callers. The immediate wrapper in `PaintAIManager.dll`\n\nhas this symbolized signature:\n\n```\nPaint::AI::AddWatermark(\n    Gdiplus::Bitmap& image,\n    winrt::guid const& watermarkId);\n```\n\n`winrt::guid`\n\n, yikes! Now we know that the 16-byte watermark payload is indeed a GUID.\n\nFurther tracking the source, we find that the GUID actually comes from a network request. Before Paint runs the local image model, `AIServices.dll`\n\nsends the prompt and style to:\n\n```\nhttps://apsaiservices-a0fqcjc6bzbhgdcd.b02.azurefd.net/\nv1/paint-cocreator/moderate-prompt\n```\n\nThe request is JSON and contains at least these fields:\n\n```\n{\n  \"prompt\": \"...\",\n  \"style\": \"...\",\n  \"lastPromptGenerationId\": \"...\"\n}\n```\n\nThe response parser expects:\n\n```\n{\n  \"revisedPrompt\": \"...\",\n  \"promptGenerationId\": \"...\",\n  \"watermarkId\": \"...\",\n  \"containsHumanReference\": false\n}\n```\n\nStatic analysis is nice, but at this point I wanted to see a real response from the server. I reused Paint’s own authenticated session and sent the following prompt through the moderation endpoint:\n\n```\na cobalt blue circle above a tiny orange square\n```\n\nThe server returned HTTP 200:\n\n```\n{\n  \"revisedPrompt\": \"a cobalt blue circle above a tiny orange square\",\n  \"promptGenerationId\": \"74d9e06b-adea-43ce-85fe-186a26e2e34a\",\n  \"watermarkId\": \"83424621-03cb-40e3-9808-a9fae837156d\",\n  \"containsHumanReference\": false\n}\n```\n\nI also tried the prompt `a portrait of a smiling person wearing a blue hat`\n\n.\nThis time the response contained a different pair of\nGUIDs and `containsHumanReference`\n\nwas `true`\n\n. The field is therefore a\nserver-side classification of whether the prompt refers to a human. Paint\nparses and stores it alongside the IDs, although I found no evidence that it\ncontrols the watermarking step itself.\n\n`ParseModerateResponse`\n\nparses both ID strings as GUIDs and rejects zero values with `InvalidPromptGenerationId`\n\nor `InvalidWatermarkId`\n\n. The server’s `watermarkId`\n\nis what becomes part of the generated image:\n\n```\nPaintUI.dll\n  `-- IPromptModerationService\n        `-- PaintAIManager.dll\n              `-- AIServices.dll!ModerateAsync(...)\n                    |\n                    +-- build JSON\n                    |     +-- prompt\n                    |     +-- style\n                    |     `-- lastPromptGenerationId\n                    |\n                    +-- HTTPS POST /v1/paint-cocreator/moderate-prompt\n                    |\n                    `-- AIServices.dll!ParseModerateResponse(response)\n                          +-- revisedPrompt\n                          +-- promptGenerationId -> parse as GUID\n                          +-- watermarkId        -> parse as GUID\n                          `-- containsHumanReference\n                                |\n                                `-- PaintUI stores WatermarkId\n                                      `-- StableDiffusionHelpers::GenerateAsync(..., watermarkId, ...)\n                                            `-- local Stable Diffusion result\n                                                  `-- Paint::AI::AddWatermark(bitmap, winrt::guid const&)\n                                                        `-- WmkWriteWatermark(..., guid, 16, ...)\n                                                              `-- modified RGB pixels\n```\n\nIn other words, “generated locally” does not mean that the complete operation is local. Microsoft receives and moderates the prompt, then issues the unique GUID that Paint embeds into the locally generated image. Paint also sends the previous `promptGenerationId`\n\nas `lastPromptGenerationId`\n\nwith its next moderation request, allowing successive requests to be linked explicitly.\n\n## The same watermark GUID in C2PA metadata\n\nThere is another piece to this story. Paint does more than alter the pixels. It also attaches [C2PA Content Credentials](https://c2pa.org/) to the saved file. The code responsible for this lives in `ProvenanceHelper.dll`\n\n, backed by `provenancesdk.dll`\n\n.\n\nFor the local Stable Diffusion path, the flow looks like this:\n\n```\nlocal Stable Diffusion result\n  |\n  +-- Paint::AI::AddWatermark(bitmap, watermarkId)\n  |     `-- Watermarker.dll!WmkWriteWatermark(..., watermarkId, 16, ...)\n  |\n  `-- AIServices.dll!SignIngredientOnlineAsync(..., promptGenerationId, image, ...)\n        |\n        +-- POST /v1/paint-cocreator/image-sign\n        |     +-- imageMetadata\n        |     |     +-- PromptGenerationId\n        |     |     +-- GenerationSeed\n        |     |     +-- CreativityLevel\n        |     |     +-- AIFVersion\n        |     |     `-- moderation scores\n        |     `-- imageToSign.jpg\n        |\n        `-- ParseProvenanceResponse(...)\n              `-- server-supplied C2PA manifest\n                    `-- ProvenanceHelper::InsertManifestIngredient(...)\n                          `-- AuthoringFinalizeOutputToBufferAsync(...)\n                                `-- final image with C2PA metadata\n```\n\nNotice that the signing request sends `PromptGenerationId`\n\n, while the image already contains the separately returned `watermarkId`\n\n. The server assigned both values during moderation, so it can associate the signing request with the watermark already present in the submitted pixels.\n\nI then saved a real image directly from Paint’s Image Creator and inspected its PNG chunks. Immediately after `IHDR`\n\nwas an 18,979-byte `caBX`\n\nchunk containing a signed C2PA manifest. The interesting part was this:\n\n```\n{\n  \"c2pa.soft-binding\": {\n    \"alg\": \"com.microsoft.invismark.1\",\n    \"blocks\": [\n      {\n        \"scope\": \"the entire image\",\n        \"value\": \"83424621-03cb-40e3-9808-a9fae837156d\"\n      }\n    ]\n  },\n  \"c2pa.actions.v2\": {\n    \"actions\": [\n      {\n        \"action\": \"c2pa.watermarked\",\n        \"description\": \"Content watermarked by Microsoft Responsible AI\"\n      }\n    ]\n  }\n}\n```\n\nDecoded into something more readable, the manifest says:\n\n- Generator:\n`Microsoft Responsible AI Provenance`\n\n- AI system:\n`Azure OpenAI ImageGen`\n\n- Action:\n`c2pa.watermarked`\n\n- Algorithm:\n`com.microsoft.invismark.1`\n\n- Watermark value:\n`83424621-03cb-40e3-9808-a9fae837156d`\n\n- Description:\n`Content watermarked by Microsoft Responsible AI`\n\nThe server’s `watermarkId`\n\n, the identifier embedded into the pixels, and the C2PA `c2pa.soft-binding.value`\n\nare the same per-generation value.\n\nThat relationship is important. C2PA calls this a *soft binding*: a value derived from, or embedded into, the content so that the content can still be matched with its provenance record after the file-level manifest has been removed. For a watermark soft binding, the `value`\n\nis the watermark’s content identifier. Microsoft cryptographically signed this assertion.\n\n## Why does Paint watermark locally?\n\nAt this point, the existence of `Watermarker.dll`\n\nstarted to make more sense. Paint actually has two rather different generation paths.\n\nThe Image Creator feature I tested above uses `Azure OpenAI ImageGen`\n\n. Generation, watermarking, and provenance packaging can all happen in Microsoft’s cloud, and Paint can simply receive a finished image that already contains both the invisible watermark and C2PA manifest:\n\n```\nImage Creator\n  `-- Microsoft cloud\n        +-- content filtering\n        +-- Azure OpenAI ImageGen\n        +-- invisible watermark\n        +-- C2PA manifest\n        `-- completed image returned to Paint\n```\n\nCocreator is different. On a supported Copilot+ PC, Microsoft [says that the NPU generates the image locally](https://support.microsoft.com/en-us/windows/ai/ai-apps/use-copilot-pc-features-in-paint), while Azure online services still perform the safety checks. The feature therefore requires both a Microsoft account and an internet connection even though the actual Stable Diffusion inference runs on the device:\n\n``` php\nCocreator on a Copilot+ PC\n  |\n  +-- prompt -> Microsoft moderation service\n  |                 +-- revisedPrompt\n  |                 +-- promptGenerationId\n  |                 `-- watermarkId\n  |\n  +-- revisedPrompt + sketch -> local NPU generation\n  |\n  +-- Watermarker.dll -> embed watermarkId locally\n  |\n  `-- online provenance signing -> final C2PA manifest\n```\n\nThis is probably the reason Paint needs a local watermark implementation at all. A cloud generator can watermark its output before returning it. A local generator cannot rely on that, so Paint has to alter the locally generated pixels itself. It also explains why Paint treats a failure from `WmkWriteWatermark`\n\nas a failure of the entire generation instead of quietly returning an unmarked image.\n\nThere is another surprisingly visible sign that Microsoft designed the save path around provenance. When I save a generated result directly from the Image Creator pane, Paint offers exactly one format: PNG.\n\nAfter an AI result is applied to the Paint canvas, the available formats are still restricted to PNG, JPEG, GIF, and Paint’s own `.paint`\n\nformat. BMP—the classic Paint format—is conspicuously absent.\n\nThis lines up with the formats supported by C2PA. PNG stores its manifest in a `caBX`\n\nchunk, JPEG uses one or more `APP11`\n\nmarker segments, and GIF has its own C2PA application-extension representation. The `.paint`\n\nformat is controlled by Microsoft and can preserve whatever provenance state Paint requires. By contrast, the [C2PA specification explicitly calls out BMP](https://spec.c2pa.org/specifications/specifications/2.4/specs/ContentCredentials.html) as a classic format that cannot embed arbitrary manifest data without using an external manifest. If Paint allowed the image to be exported directly as BMP, the file-level C2PA manifest would therefore disappear.\n\nThe split also raises an interesting security question about the cloud path. If the underlying remote image-generation endpoint can be made to return the generated image before watermarking and provenance packaging—or has an internal option that suppresses those stages—it might be possible to obtain a cloud-generated image with neither signal attached.\n\nHow to classify such a path would depend entirely on Microsoft’s design goal. It could be intended behavior if the underlying service is allowed to return raw generations and Paint is merely responsible for applying the provenance layers. It could be a product bug if Microsoft overlooked the possibility of someone calling the API directly and bypassing Paint’s watermarking step. Or it could be a security vulnerability if Microsoft treats watermarking as a mandatory abuse-prevention or provenance control and the endpoint can be made to bypass it. Without knowing the intended trust boundary, all three possibilities remain open.\n\n## Photos app does the same thing\n\nWhile I was trying to locate the `Watermarker.dll`\n\non disk, I happened to notice that Microsoft Photos contains a DLL with the same name:\n\n```\nC:\\Program Files\\WindowsApps\\\n  Microsoft.Windows.Photos_2026.11060.2004.0_x64__8wekyb3d8bbwe\\Watermarker.dll\n```\n\nThere are also local Stable Diffusion operations behind Photos’ Image Creator and Restyle Image features. Both lead to the same watermark wrapper:\n\n```\nPhotos Image Creator\n  `-- PerformSDTextToImageAndWatermarkAsync(..., promptGenerationId, ...)\n        +-- run the local text-to-image model\n        `-- ApplyWatermark(image, promptGenerationId)\n              +-- parse promptGenerationId as a GUID\n              +-- ConvertGUIDtoContiguousByteArray()\n              +-- convert RGBA to ARGB\n              +-- Watermarker.dll!WmkWriteWatermark(..., guid, 16, ...)\n              `-- convert ARGB back to RGBA\n```\n\nRestyle Image takes the parallel path:\n\n```\nPhotos Restyle Image\n  `-- PerformSDSketchToImageAndWatermarkAsync(..., promptGenerationId, ...)\n        `-- ApplyWatermark(image, promptGenerationId)\n              `-- Watermarker.dll!WmkWriteWatermark(..., guid, 16, ...)\n```\n\nA subtle difference between Photos and Paint is failure behavior. If the watermark encoder returns an error, its code logs:\n\n```\nApplyWatermark encountered error: ... - watermark will not be applied.\n```\n\nIt then appears to continue returning the generated image. Paint instead treats a watermarking failure as a generation failure and the image is not returned to the user.\n\n## What Microsoft discloses\n\nAfter doing this analysis, I found that Microsoft does disclose some adjacent parts of the system on its [Image Creator support page](https://support.microsoft.com/en-us/windows/ai/ai-apps/use-image-creator-in-paint-to-generate-ai-art). On content filtering, it says:\n\n“we apply content filtering to prevent the generation of images”\n\nThe same page says that generated images:\n\n“will contain C2PA manifest helping users identify that it is an AI generated image.”\n\nIt also explains that Image Creator uses Azure online services and says Microsoft collects user and device identifiers together with prompts for abuse prevention and monitoring. That is a meaningful disclosure of remote filtering and C2PA metadata.\n\nWhat the page does not explain is that the C2PA manifest contains a GUID identifying the invisible pixel watermark, or that Paint’s local generation path receives its watermark GUID from remote prompt moderation. Calling the feature “Content Credentials” is accurate, but it does not make this prompt-associated identifier obvious to a Windows user.\n\n## Conclusion\n\nTo the best of my knowledge, this is the first research to document and analyze the invisible-watermarking behavior of Paint and Photos. Visible watermarks on AI-generated images are not new—Microsoft documents them for [Microsoft 365](https://support.microsoft.com/en-us/topic/include-a-watermark-when-content-from-microsoft-365-is-ai-generated-b00a656e-ae61-4692-8086-67d004421030) and [Bing Image Creator](https://www.microsoft.com/en-us/bing/features/bing-image-creator/)—nor are invisible pixel watermarks such as [Google’s SynthID](https://deepmind.google/models/synthid/) and [Bing’s hidden watermark](https://cdn-dynmedia-1.microsoft.com/is/content/microsoftcorp/microsoft/final/en-us/microsoft-brand/documents/August-2024-Microsoft-Bing-Systemic-Risk-Assessment-Report-EU-Digital-Services-Act.pdf).\n\nMicrosoft does disclose that Paint uses remote content filtering and adds C2PA Content Credentials. The new evidence shows that this metadata is not merely an unrelated file-level AI label: its signed `c2pa.soft-binding`\n\nassertion names Microsoft InvisMark and records the identifier carried by the invisible pixel watermark. The file-level manifest and pixel-level watermark are two layers of the same provenance system.\n\nThe local and cloud paths also explain the unusual division of labor. Cloud Image Creator can return an already watermarked and signed image, while Cocreator must embed the server-issued identifier after local NPU inference. In both cases, “local” does not mean offline: the prompt still goes to Microsoft for moderation, and the completed local result goes through online provenance signing.\n\nThis might be related to [Article 50 of the EU AI Act](https://digital-strategy.ec.europa.eu/en/policies/code-practice-ai-generated-content), whose transparency rules took effect on August 2, 2026 and require AI-generated content to carry a detectable, machine-readable mark—but not a prompt-specific GUID. Microsoft discloses the existence of C2PA metadata, but I could not find a disclosure explaining the server-issued watermark GUID, its association with prompt moderation, or its presence in the pixels. Those details carry obvious privacy and right-to-know implications.\n\nIt also appears possible to modify Paint or Photos to bypass both prompt moderation and watermarking. But that does not provide a new capability: anyone can already run Stable Diffusion directly without either mechanism.", "url": "https://wpnews.pro/news/ms-paint-and-photos-inivisibly-watermark-even-locally-generated-output-with-guid", "canonical_source": "https://xusheng.dev/posts/reversing/mspaint_invisible_watermark/main/", "published_at": "2026-08-24 15:28:04+00:00", "updated_at": "2026-08-24 16:12:54.355884+00:00", "lang": "en", "topics": ["artificial-intelligence", "ai-policy", "ai-products"], "entities": ["Microsoft", "Paint", "Photos", "Copilot+", "C2PA", "xusheng.dev", "Binary Ninja MCP", "Codex"], "alternates": {"html": "https://wpnews.pro/news/ms-paint-and-photos-inivisibly-watermark-even-locally-generated-output-with-guid", "markdown": "https://wpnews.pro/news/ms-paint-and-photos-inivisibly-watermark-even-locally-generated-output-with-guid.md", "text": "https://wpnews.pro/news/ms-paint-and-photos-inivisibly-watermark-even-locally-generated-output-with-guid.txt", "jsonld": "https://wpnews.pro/news/ms-paint-and-photos-inivisibly-watermark-even-locally-generated-output-with-guid.jsonld"}}