GitHub Advisoryadvisory · Packagist

GHSA-6jq6-x4cx-qvcm Firefly II has Stored XSS in Audit Log Entry view via piggy bank name (ale.twig)

MEDIUM Published 2026-06-12 Modified 2026-06-12 Official page ↗
Ecosystem
Packagist
Packages
grumpydictator/firefly-iii
Severity
Moderate
CVSS vector
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
Weaknesses
CWE-116, CWE-79
Reviewed
2026-06-12

Affected packages

• Packagist grumpydictator/firefly-iii: < 6.6.3 → fixed in 6.6.3

Description

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 `` 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): ```twig {{ 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": ""} → 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 `` payload bypasses the nonce requirement entirely. PoC 1. Authenticate as any user 2. `POST /api/v1/piggy-banks` with `"name": ""` 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): ```html Added EUR 50.00 to piggy bank "" ``` 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. ```twig {{ trans('firefly.ale_action_log_add', { amount: formatAmountBySymbol(...), name: logEntry.after.piggy|e })|raw }} ```

Related

Weakness · CWE (2)

  • CWE-116 Improper Encoding or Escaping of Output weakness
  • CWE-79 Improper Neutralization of Input During Web Page Generation weakness

References