GHSA-3h6j-9x8m-rg3g

Suggest an improvement
Source
https://github.com/advisories/GHSA-3h6j-9x8m-rg3g
Import Source
https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2026/03/GHSA-3h6j-9x8m-rg3g/GHSA-3h6j-9x8m-rg3g.json
JSON Data
https://api.osv.dev/v1/vulns/GHSA-3h6j-9x8m-rg3g
Published
2026-03-31T23:12:36Z
Modified
2026-03-31T23:32:26Z
Severity
  • 2.1 (Low) CVSS_V4 - CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:P/VC:N/VI:N/VA:N/SC:L/SI:L/SA:N/E:P CVSS Calculator
Summary
Graby has stored XSS via iframe srcdoc Attribute in htmLawed Sanitization Config
Details

Summary

Graby's cleanupXss() function configures htmLawed with conflicting settings: safe=1 (which removes <iframe>) combined with 'elements' => '*+iframe-meta' (which re-enables <iframe>). htmLawed does not sanitize the srcdoc attribute, allowing injection of arbitrary JavaScript that executes when the content is rendered via |raw in templates.

Root Cause

src/Graby.php lines 1038-1048:

htmLawed($html, [
    'safe' => 1,                    // removes <iframe>
    'elements' => '*+iframe-meta',  // re-adds <iframe>, overrides safe=1
    'deny_attribute' => 'style',    // srcdoc is NOT denied
]);

The safe=1 and +iframe combination is a conflict: safe mode is designed to strip dangerous elements, but the elements override re-enables <iframe> without also blocking the dangerous srcdoc attribute.

Proof of Concept

Input to cleanupXss():

<iframe srcdoc="&lt;script&gt;alert(document.domain)&lt;/script&gt;"></iframe>

Output (unchanged — htmLawed passes it through):

<iframe srcdoc="&lt;script&gt;alert(document.domain)&lt;/script&gt;"></iframe>

When rendered via {{ content|raw }} in a template, srcdoc executes in an about:srcdoc frame with the same origin as the page. Confirmed via Puppeteer/Chromium headless: alert(document.domain) fires.

Validated on Wallabag (which uses Graby) via Docker: entry created via API with iframe-only content body triggers Readability failure → falls through to cleanupXss() path.

Impact

  • Stored XSS in any application rendering Graby-sanitized content via |raw
  • In Wallabag: affects both authenticated views and public share pages (unauthenticated)
  • No CSP headers in default Wallabag config — no secondary mitigation

Suggested Fix

Either remove +iframe from the elements config to keep iframes blocked:

'elements' => '*-iframe-meta',

Or explicitly deny the srcdoc attribute:

'deny_attribute' => 'style srcdoc',

Credit

Discovered by @tikket1, 2026-03-25. Redirected from wallabag/wallabag advisory by @j0k3r.

Database specific
{
    "cwe_ids":  [
        "CWE-79"
    ],
    "github_reviewed":  true,
    "github_reviewed_at":  "2026-03-31T23:12:36Z",
    "nvd_published_at":  null,
    "severity":  "LOW"
}
References

Affected packages

Packagist / j0k3r/graby

Package

Name
j0k3r/graby
Purl
pkg:composer/j0k3r/graby

Affected ranges

Type
ECOSYSTEM
Events
Introduced
0 Unknown introduced version / All previous versions are affected
Fixed
2.5.1

Affected versions

1.*
1.0.0-alpha.0
1.0.0-alpha.1
1.0.0-alpha.2
1.0.0
1.0.1
1.0.2
1.0.3
1.0.4
1.0.5
1.0.6
1.0.7
1.0.8
1.1.0
1.2.0
1.3.0
1.4.0
1.4.1
1.4.2
1.4.3
1.4.4
1.4.5
1.5.0
1.5.1
1.5.2
1.5.3
1.5.4
1.6.0
1.6.1
1.6.2
1.7.0
1.7.1
1.8.0
1.8.1
1.8.2
1.9.0
1.9.1
1.9.2
1.9.3
1.10.0
1.10.1
1.11.0
1.11.1
1.12.0
1.12.1
1.13.0
1.13.1
1.13.2
1.13.3
1.13.4
1.13.5
1.13.6
1.14.0
1.15.0
1.15.1
1.15.2
1.15.3
1.15.4
1.15.5
1.16.0
1.17.0
1.18.0
1.18.1
1.19.0
1.19.1
1.20.0
1.20.1
2.*
2.0.0-alpha.0
2.0.0
2.0.1
2.0.2
2.1.0
2.1.1
2.2.0
2.2.1
2.2.4
2.2.5
2.2.6
2.2.7
2.3.0
2.3.1
2.3.2
2.3.3
2.3.4
2.3.5
2.4.0
2.4.1
2.4.2
2.4.3
2.4.4
2.4.5
2.4.6
v2.*
v2.2.2
v2.2.3
v2.5.0

Database specific

last_known_affected_version_range
"<= 2.5.0"
source
"https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2026/03/GHSA-3h6j-9x8m-rg3g/GHSA-3h6j-9x8m-rg3g.json"