Common Path Traversal in Accounting Apps: Causes and Fixes
Path traversal happens when an app accepts a file name, path, document ID, or archive entry from the user and uses it directly to read, write, or delete files on the server, device, or cloud storage b
What causes path traversal in accounting apps
Path traversal happens when an app accepts a file name, path, document ID, or archive entry from the user and uses it directly to read, write, or delete files on the server, device, or cloud storage bucket.
In accounting apps, the risk is higher because file handling is central to the product. Users regularly upload receipts, bank statements, tax forms, payroll exports, invoice PDFs, audit logs, and reconciliation files. If path handling is weak, attackers may reach files they should never access.
Common technical root causes include:
- Concatenating user input into file paths instead of using safe path resolution.
- Accepting raw file names such as
receipt.pdf,../../taxes/payroll.csv, or encoded variants. - Using predictable storage paths like
/invoices/2025/invoice-1001.pdf. - Extracting ZIP or CSV imports without validating archive entries.
- Mixing tenant data in shared storage directories for multi-company accounting systems.
- Using local filesystem paths in mobile apps instead of sandboxed app storage.
- Trusting document URLs or signed URLs that can be manipulated to point at other objects.
- Failing to canonicalize paths before checking access.
The core issue is not just “special characters.” The real issue is that the app treats user-controlled data as a trusted filesystem instruction.
Real-world impact
For accounting apps, path traversal is rarely an abstract vulnerability. It can expose sensitive financial data and break customer trust.
Typical user-facing impact includes:
- Exposure of invoices, receipts, tax documents, payroll files, and bank statements
- Unauthorized access to another company’s records in multi-tenant SaaS products
- Tampered financial exports used for reconciliation, tax filing, or audit reporting
- Deleted or overwritten attachments needed for compliance evidence
- Leaked API credentials or configuration files from server-side storage
- App crashes or ANRs when mobile clients request invalid file paths
- Failed uploads and broken invoice previews, causing support tickets
- Poor store ratings when users report missing receipts, broken reports, or security concerns
Revenue impact can be direct. A SaaS accounting platform may lose annual contracts after a data exposure. A mobile bookkeeping app may see uninstall spikes after users discover that invoice attachments or tax documents are accessible through malformed requests. Audit-driven customers may also require incident reviews, compensating controls, or contractual penalties.
How path traversal manifests in accounting apps
| Accounting feature | Path traversal pattern | Why it matters |
|---|---|---|
| Invoice PDF downloads | GET /api/invoices/1001/download?file=../../2025/tax-return.pdf | Exposes tax documents or other companies’ invoices |
| Receipt image uploads | POST /receipts/upload with filename ../../shared/logo.png | Overwrites or reads files outside the intended receipt folder |
| Bank statement import | ZIP entry ../../config/.env or ../../exports/payroll.csv | Leaks credentials or financial exports during archive extraction |
| Payroll report export | GET /reports/payroll?path=/reports/2025/all-employees.csv | Reveals salaries, bonuses, tax IDs, and employee banking details |
| Audit log viewer | GET /audit-log?file=../../../logs/admin.log | Exposes authentication events, admin actions, or internal errors |
| Attachment preview | GET /preview?doc=../customerA/invoice.pdf | Breaks tenant isolation in SaaS accounting systems |
| Mobile document cache | Deep link opens content:// or file URI outside app sandbox | Exposes cached receipts, statements, or generated PDFs |
The most dangerous examples usually appear in features that sound routine: “download report,” “import CSV,” “view attachment,” or “export invoices.”
How to detect path traversal
Start by mapping every feature that handles files. In accounting apps, review:
- Invoice and receipt downloads
- Bank statement imports
- Payroll and tax exports
- Audit log downloads
- Attachment previews
- Document signing flows
- Mobile file pickers and deep links
- ZIP, CSV, and XLSX import pipelines
Then test both the API and UI layer.
Useful techniques:
- Manual API testing with Burp Suite or OWASP ZAP: modify file names, document IDs, and query parameters.
- Encoded payload checks: test
../,%2e%2e%2f,..%252f, backslashes, and mixed separators. - Archive extraction tests: inspect ZIP entries for paths outside the target directory.
- Tenant isolation tests: try accessing another company’s invoice, receipt, or report using the same authenticated session.
- Static analysis: use Semgrep, CodeQL, or IDE rules to find unsafe file APIs.
- Mobile testing: inspect Android APK storage access, exported activities, deep links, and local file URIs.
- DAST automation: run authenticated scans against staging with realistic accounting workflows.
- Regression test generation: convert discovered file flows into repeatable Appium or Playwright tests.
Look for these warning signs in code and logs:
FileInputStream(userInput)Path.resolve(userInput)open(userFilename)sendFile(req.query.file)Path.of(base, filename)without normalizationZipEntry.getName()used directly- Predictable object storage keys based on invoice numbers
- Missing tenant checks before file access
- Missing
startsWithchecks after path normalization
How to fix each example
1. Invoice PDF downloads
Do not let users pass file paths. Store invoice metadata in the database and resolve the file server-side.
Unsafe pattern:
Path file = Paths.get("/data/invoices/" + request.query("file"));
Safer pattern:
Path base = Paths.get("/data/invoices").toAbsolutePath().normalize();
Path requested = base.resolve(userId).resolve(invoiceId).resolve("invoice.pdf").normalize();
if (!requested.startsWith(base)) {
throw new SecurityException("Invalid invoice path");
}
Better still, use a database record such as invoice_id, tenant_id, and storage_key, then verify that the authenticated user belongs to that tenant before serving the file.
2. Receipt image uploads
Never trust uploaded filenames. Generate a random object key and store the original filename separately for display only.
Recommended approach:
safe_name = f"{tenant_id}/{user_id}/{uuid.uuid4()}.jpg"
Validate MIME type, size, and image dimensions. Store receipts in tenant-scoped storage, not shared folders.
3. Bank statement ZIP imports
Zip Slip is a common path traversal variant. Every archive entry must be checked before extraction.
Unsafe pattern:
Path destination = Paths.get(uploadDir, entry.getName());
Safer pattern:
Path base = uploadDir.toAbsolutePath().normalize();
Path destination = base.resolve(entryName).normalize();
if (!destination.startsWith(base)) {
throw new SecurityException("Unsafe archive entry");
}
Also reject absolute paths, entries with .., and symbolic links unless your importer explicitly supports them.
4. Payroll and tax report exports
Payroll exports contain salaries, tax IDs,
Test Your App Autonomously
Upload your APK or URL. SUSA explores like 10 real users — finds bugs, accessibility violations, and security issues. No scripts.
Try SUSA Free