Summary
Grocy's API request-body parser can undo HTML entity encoding after input has been purified, allowing dangerous markup to be reconstructed in stored field values. When affected data is later rendered without re-sanitization, an attacker may execute script in the context of users viewing products, recipes, stock, users, chores, or other records.
Affected context
The vulnerability occurs in Grocy deployments where API-writable fields pass through the affected request-body parsing path and are subsequently displayed by application views without an additional context-appropriate output encoding or sanitization step. Risk depends on whether an attacker can submit or modify records through an exposed API and whether other users or administrators later view the stored content.
Exploit preconditions
- Attack surface: Grocy API endpoints that accept writable request-body fields
- Required access: Ability to submit or modify API data, subject to the deployment's authentication and authorization controls
- Trigger point: Request-body parsing followed by storage and later rendering of the affected value
- Why exploitation is possible: HTMLPurifier output is manually double-decoded, reconstructing markup that the purifier had encoded to prevent active HTML or script content
Why this happens
The underlying bug is an inconsistent sanitization pipeline. After HTMLPurifier neutralizes potentially active markup by entity-encoding it, subsequent replacements convert encoded ampersands, angle brackets, and related sequences back into live characters.
This defeats the intended protection and maps to CWE-79: Improper Neutralization of Input During Web Page Generation, because attacker-controlled content can survive storage and become executable when inserted into a browser-rendered context.
Potential impact
- An attacker may execute JavaScript in the browser of a user viewing a poisoned record.
- A malicious value could perform actions available to the victim's session.
- Administrative users may be targeted through stored content in commonly viewed records.
- Sensitive information accessible to the victim's browser session could be exposed.
- Stored malicious content could affect multiple users and persist until removed.
General mitigation guidance
Mitigation generally focuses on preserving a single, well-defined output-safety model throughout the data lifecycle.
Common defensive patterns include:
- Avoiding manual entity decoding after sanitization.
- Applying context-specific output encoding at every HTML, attribute, URL, or script insertion point.
- Treating API input as untrusted even when it has passed an input purifier.
- Using allowlisted, context-aware sanitization only where rich text is explicitly required.
- Separating stored data from rendered markup and enforcing safe rendering primitives.
- Limiting API permissions and applying least privilege to accounts that can modify records.
- Using browser security controls such as an appropriately restrictive Content Security Policy as defense in depth.
How teams detect issues like this
Detection approaches can include:
- Static analysis for manual replacements that decode HTML entities after sanitization.
- Code review checks for values sanitized once and later rendered without context-specific encoding.
- Tests that submit encoded markup and verify that it remains inert after parsing, storage, and rendering.
- Dynamic application testing across API-writable fields and all views that display them.
- Policy enforcement requiring approved output-encoding or sanitization utilities at rendering boundaries.
- Neutral automated code-review tools that flag dangerous decode-after-sanitize data flows.

