GitHub Advisoryadvisory · Packagist
GHSA-6jq6-x4cx-qvcm Firefly II has Stored XSS in Audit Log Entry view via piggy bank name (ale.twig)
MEDIUM
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 }}
```