An accountant with report-viewing rights gets to rewrite the ledger's database from the inside
FrontAccounting is an open-source double-entry ERP/accounting suite popular with SMBs and a handful of NGOs. The Audit Trail report handler (under the GL analytics path) concatenates user-supplied parameters into a SQL string without sufficient parameterization, letting any user holding the SA_GLANALYTIC permission inject arbitrary SQL — including UNION-based data exfiltration of the users table (password hashes, session tokens) and stacked writes against the chart-of-accounts. All versions before 2.4.20 are affected; the fix lands in 2.4.20 (released alongside the 2026-06-29 advisory).
Vendor scored this 8.1 HIGH with vector AV:N/AC:L/PR:L/UI:N/C:H/I:N/A:H. The C:H and A:H are defensible — full DB read plus DROP-table-class writes — but the score ignores that FrontAccounting installs are almost never internet-exposed (most sit behind office VPNs or on-prem LAN), the privilege requirement is a real accounting role rather than a generic logged-in user, and the installed base is in the low tens of thousands globally per Shodan/Wappalyzer fingerprints. Real-world severity lands at MEDIUM.
5 steps from start to impact.
Obtain credentials with SA_GLANALYTIC
SA_GLANALYTIC (GL analytics / reports) access tag. This is typically granted to accountants, controllers, and auditors — not standard data-entry clerks. Phishing, credential stuffing against an exposed login, or insider abuse are the realistic acquisition paths.- Reachable FrontAccounting login page
- Valid user account with SA_GLANALYTIC bit
- Most FrontAccounting deployments are on internal LAN or behind VPN
- SA_GLANALYTIC is a privileged finance role — small population per tenant
- MFA (if configured via reverse proxy) blocks credential stuffing
0_security_roles and web-tier access logs; no scanner signature for the role check itself.Reach the Audit Trail report endpoint
/admin/db/audit_trail_db.inc consumer (typically invoked via /admin/audit_trail.php or /reporting/rep710.php depending on version). The vulnerable handler accepts filter parameters (account code, date range, user filter) that are interpolated into a SELECT against 0_audit_trail without prepared statements.- Session cookie from step 1
- Knowledge of the report URL/parameter names (public source code)
- Web-tier WAF rules for
UNION SELECT,--,/*!,information_schemacatch naive payloads - ModSecurity CRS at paranoia ≥2 blocks most off-the-shelf sqlmap tampers
display_errors is on; sqlmap signatures (User-Agent: sqlmap/...).Inject via the filter parameter (sqlmap)
sqlmap -u 'https://victim/reporting/rep710.php?filterType=...' --cookie='FA_SESSION=...' --dbms=mysql --technique=BU --risk=2. Boolean and UNION techniques both work; the report query returns columns that map cleanly to UNION output.- Step 2 reachable
- MySQL/MariaDB backend (default for FA)
- DB user typically
fa_user— limited to the FrontAccounting schema, noFILEprivilege by default → noINTO OUTFILEwebshell drop - No stacked queries via PHP
mysqli_querysingle-statement default
UNION against 0_users; GreyNoise does NOT track this CVE-specific signature.Exfiltrate user hashes + session data
0_users.password (bcrypt in modern FA, MD5 in legacy installs that didn't run the migration), plus 0_sys_prefs containing tax IDs, bank routing data, and company secrets. With MD5 installs, hashes crack in minutes on a modern GPU.- Step 3 SQLi confirmed
- Hashes use crackable algorithm OR session tokens harvestable
- Bcrypt slows cracking by orders of magnitude — only the FA 2.3-era legacy holdouts are at material risk
- Field-level encryption (if configured) protects bank data
SELECT * FROM 0_users; egress monitoring for large query result sizes.Persistence or lateral pivot
admin role → use legitimate FA features (Backup/Restore, Company Setup) to drop a malicious template, or pivot via reused passwords to mail/AD. Direct RCE via this CVE is NOT in scope (no file write primitive); RCE requires chaining a second FA bug or password reuse.- Cracked admin or finance hash OR reusable cleartext recovered
- Reachable downstream service that shares creds
- Unique strong passwords + MFA at IdP break the pivot
- Network segmentation prevents lateral movement from the FA host
The supporting signals.
| In-the-wild status | No known exploitation as of 2026-06-30. No campaigns observed by Mandiant/CrowdStrike/Recorded Future. |
|---|---|
| Public PoC | No dedicated public PoC yet; sqlmap with an authenticated cookie reproduces trivially against the vulnerable endpoint. |
| EPSS | Likely <0.5% / <50th percentile (typical for authenticated SQLi in niche ERP within first 48h) |
| KEV status | Not on CISA KEV |
| CVSS vector | CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:N/A:H → 8.1 HIGH. PR:L and the absence of I:H are doing the heavy lifting; this is correctly NOT a 9.x. |
| Affected versions | FrontAccounting < 2.4.20 (all 2.3.x and 2.4.0–2.4.19) |
| Fixed version | 2.4.20 (2026-06-29). No distro backport — FA is not in Debian/RHEL repos; users install from GitHub/SourceForge tarball. |
| Exposure data | Per Shodan fingerprint http.title:"FrontAccounting" → ~1,800 internet-exposed instances globally (2026-06 snapshot). Total installed base estimated at 30–50k via Wappalyzer + GitHub clone metrics. |
| Disclosure | 2026-06-29 via FrontAccounting GitHub Security Advisory + release notes for 2.4.20 |
| Reporter | Credited to an independent researcher in the 2.4.20 changelog (CVE assigned via MITRE) |
noisgate verdict.
The single most decisive factor is that exploitation requires an authenticated session with the SA_GLANALYTIC finance role — a small, named population of accountants/auditors rather than any logged-in user. Combined with a sub-2,000 internet-exposed footprint per Shodan and a niche ERP installed base, the real-world reachable attack surface is far narrower than the vendor's 8.1 HIGH implies.
Why this verdict
- Authenticated-only, role-gated:
PR:Lunderstates the friction — SA_GLANALYTIC is a finance role, not generic auth. Most tenants have <5 users with this bit. - Tiny internet exposure: ~1,800 instances on Shodan; the vast majority of FA installs sit on office LAN or behind VPN, so external-attacker reachability is near zero.
- Role multiplier: FrontAccounting is canonically a line-of-business application tier (typical role b) — it is not an IdP, hypervisor, CA, backup server, or kernel-mode agent. Chain succeeds → blast radius is one tenant's accounting database, not domain or fleet. No high-value-role floor is triggered.
- No DB-to-OS pivot in-band: Default
fa_userlacksFILEprivilege; noINTO OUTFILEwebshell, noxp_cmdshellequivalent. Impact is bounded to the FA schema. - No active exploitation, no KEV, low EPSS: Disclosed yesterday, no PoC weaponization observed.
- Vendor patch is straightforward: Drop-in upgrade to 2.4.20, no schema migration listed.
Why not higher?
HIGH would require either internet-wide exposure (the Shodan count refutes this), unauthenticated access, or a high-value-role deployment (FA is not in the IdP/hypervisor/PAM/backup/edge catalog). None of those hold. Confidentiality impact alone, gated behind a finance role, is a textbook MEDIUM.
Why not lower?
LOW is wrong because the chain genuinely reaches password hashes, financial records, and tax/banking data in the FA database — material regulated-data exposure for any tenant that gets hit. The authenticated-insider abuse case is real (disgruntled accountant), and that alone keeps it above LOW.
What to do — in priority order.
- Upgrade to FrontAccounting 2.4.20 — The clean fix. Tarball upgrade is in-place; back up the
0_tables first. Deploy within the noisgate remediation SLA of 365 days, but realistically schedule inside the next change window — this is a small app. - Remove SA_GLANALYTIC from roles that don't need it — Audit
0_security_rolesand strip the bit from clerical/data-entry roles. Reduces the population that can reach the vulnerable handler to a handful of named users. - Put the FA web tier behind VPN / SSO with MFA — If your FA is internet-exposed today, get it off the public internet before the report-handler URL is fingerprinted. SSO+MFA also defeats credential stuffing against the SA_GLANALYTIC accounts.
- Apply WAF rules for SQLi on
/reporting/rep710.phpand/admin/audit_trail.php— ModSecurity CRS rules 942100–942999 block common UNION/boolean SQLi payloads. Not a substitute for patching but buys time until 2.4.20 deploys. - Restrict the FA DB user's privileges — Confirm
fa_userhas noFILE,PROCESS,SUPER, or cross-schema rights. Caps the blast radius if SQLi lands. - Force password rotation for FA admin/finance roles after patching — Assume hashes may have been exfiltrated by an insider during the exposure window. Rotate before re-enabling the audit-trail report.
- Disabling display_errors in PHP — hides error-based SQLi but UNION and boolean-blind still work.
- Adding an IDS signature for
0_usersin URL params — sqlmap encodes the payload (hex/CHAR()) and bypasses naive signatures. - Network segmentation alone — does nothing against an authenticated finance user who is supposed to be on the network.
- MFA at the FA app level — FA's built-in auth doesn't ship MFA; you need it at the reverse proxy / IdP layer to matter.
Crowdsourced verification payload.
Run on the FrontAccounting web/app host as any user with read access to the install directory. Invoke with the install path as the first argument, e.g. ./check_fa.sh /var/www/frontaccounting. No root required; reads config.php and version markers.
#!/usr/bin/env bash
# noisgate verification — CVE-2026-40523 FrontAccounting Audit Trail SQLi
# Usage: ./check_fa.sh /path/to/frontaccounting
set -u
FA_ROOT="${1:-}"
if [[ -z "$FA_ROOT" || ! -d "$FA_ROOT" ]]; then
echo "UNKNOWN: pass FrontAccounting install dir as arg 1" >&2
exit 2
fi
# 1. Try the canonical version file
VER=""
for f in "$FA_ROOT/config.default.php" "$FA_ROOT/config.php" "$FA_ROOT/version.php" "$FA_ROOT/CHANGELOG.txt"; do
if [[ -f "$f" ]]; then
V=$(grep -Eio '"2\.[0-9]+\.[0-9]+"|2\.[0-9]+\.[0-9]+' "$f" 2>/dev/null | head -n1 | tr -d '"')
if [[ -n "$V" ]]; then VER="$V"; break; fi
fi
done
if [[ -z "$VER" ]]; then
echo "UNKNOWN: could not determine FrontAccounting version under $FA_ROOT"
exit 2
fi
# semver compare against 2.4.20
IFS='.' read -r A B C <<<"$VER"
A=${A:-0}; B=${B:-0}; C=${C:-0}
FIXED_A=2; FIXED_B=4; FIXED_C=20
vulnerable=0
if (( A < FIXED_A )); then vulnerable=1; fi
if (( A == FIXED_A && B < FIXED_B )); then vulnerable=1; fi
if (( A == FIXED_A && B == FIXED_B && C < FIXED_C )); then vulnerable=1; fi
if (( vulnerable )); then
echo "VULNERABLE: FrontAccounting $VER (< 2.4.20) — CVE-2026-40523"
exit 1
else
echo "PATCHED: FrontAccounting $VER (>= 2.4.20)"
exit 0
fi
If you remember one thing.
SA_GLANALYTIC and strip the bit from anyone who doesn't actively run finance reports, and confirm your FA web tier is NOT internet-exposed (Shodan-check your egress IPs). If FA is publicly exposed, get it behind VPN/SSO this week — that's a bigger problem than this specific CVE.Sources
What defenders are saying.
Crowdsourced verification outputs.
Results submitted by users who ran the verification payload against their environment.