Medium severity6.5NVD Advisory· Published Mar 9, 2026· Updated Apr 9, 2026
CVE-2026-3089
CVE-2026-3089
Description
Actual Sync Server allows authenticated users to upload files through POST /sync/upload-user-file. In versions prior to 26.3.0, improper validation of the user-controlled x-actual-file-id header means that traversal segments (../) can escape the intended directory and write files outside userFiles.This issue affects prior versions of Actual Sync Server 26.3.0.
Affected packages
Versions sourced from the GitHub Security Advisory.
| Package | Affected versions | Patched versions |
|---|---|---|
@actual-app/sync-servernpm | < 26.3.0 | 26.3.0 |
Affected products
1Patches
118072e1d8b52Validate file IDs for correctness (#7067)
3 files changed · +42 −0
packages/sync-server/src/app-sync.test.ts+23 −0 modified@@ -366,6 +366,19 @@ describe('/upload-user-file', () => { expect(res.text).toBe('fileId is required'); }); + it('returns 400 for invalid fileId format', async () => { + const res = await request(app) + .post('/upload-user-file') + .set('Content-Type', 'application/encrypted-file') + .set('x-actual-token', 'valid-token') + .set('x-actual-name', 'test-file') + .set('x-actual-file-id', 'budget@2026') + .send(Buffer.from('file content')); + + expect(res.statusCode).toEqual(400); + expect(res.text).toBe('invalid fileId'); + }); + it('uploads a new file successfully', async () => { const fileId = crypto.randomBytes(16).toString('hex'); const fileName = 'test-file.txt'; @@ -670,6 +683,16 @@ describe('/download-user-file', () => { expect(res.text).toBe('User or file not found'); }); + it('returns 400 for invalid fileId format', async () => { + const res = await request(app) + .get('/download-user-file') + .set('x-actual-token', 'valid-token') + .set('x-actual-file-id', 'budget@2026'); + + expect(res.statusCode).toEqual(400); + expect(res.text).toBe('invalid fileId'); + }); + it('returns 500 error if the file does not exist on the filesystem', async () => { getAccountDb().mutate( 'INSERT INTO files (id, deleted) VALUES (?, FALSE)',
packages/sync-server/src/app-sync.ts+13 −0 modified@@ -49,11 +49,16 @@ app.use(express.json({ limit: `${config.get('upload.fileSizeLimitMB')}mb` })); export { app as handlers }; const OK_RESPONSE = { status: 'ok' }; +const FILE_ID_PATTERN = /^[A-Za-z0-9_-]+$/; function boolToInt(deleted) { return deleted ? 1 : 0; } +function isValidFileId(fileId: unknown): fileId is string { + return typeof fileId === 'string' && FILE_ID_PATTERN.test(fileId); +} + const verifyFileExists = (fileId, filesService, res, errorObject) => { try { return filesService.get(fileId); @@ -256,6 +261,10 @@ app.post('/upload-user-file', async (req, res) => { res.status(400).send('fileId is required'); return; } + if (!isValidFileId(fileId)) { + res.status(400).send('invalid fileId'); + return; + } let groupId = req.headers['x-actual-group-id'] || null; const encryptMeta = req.headers['x-actual-encrypt-meta'] || null; @@ -352,6 +361,10 @@ app.get('/download-user-file', async (req, res) => { res.status(400).send('Single file ID is required'); return; } + if (!isValidFileId(fileId)) { + res.status(400).send('invalid fileId'); + return; + } const filesService = new FilesService(getAccountDb()); const file = verifyFileExists(
upcoming-release-notes/7067.md+6 −0 added@@ -0,0 +1,6 @@ +--- +category: Bugfixes +authors: [jfdoming] +--- + +Validate file IDs for correctness
Vulnerability mechanics
Generated by null/stub on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
6- github.com/actualbudget/actual/pull/7067nvdIssue TrackingPatchWEB
- fluidattacks.com/advisories/fuguenvdExploitThird Party AdvisoryWEB
- github.com/advisories/GHSA-27vg-33gh-4hwgghsaADVISORY
- nvd.nist.gov/vuln/detail/CVE-2026-3089ghsaADVISORY
- github.com/actualbudget/actual/commit/18072e1d8b5281db43ded8b21433ee177bae9dfaghsaWEB
- github.com/actualbudget/actual/security/advisories/GHSA-27vg-33gh-4hwgghsaWEB
News mentions
50- The Boring Stuff is Dangerous NowDark Reading · May 18, 2026
- Russian hackers turn Kazuar backdoor into modular P2P botnetBleepingComputer · May 16, 2026
- Nobody believes the 'criminals and scumbags' who hacked Canvas really deleted stolen student dataThe Register Security · May 14, 2026
- 18-year-old NGINX vulnerability allows DoS, potential RCEBleepingComputer · May 14, 2026
- To gain root access at this company, all an intruder had to do was ask nicelyThe Register Security · May 14, 2026
- To gain root access at this company, all an intruder had to do was ask nicelyThe Register Security · May 14, 2026
- AWS to Quick admins: The access control didn't work, but you weren't using it anyway, so what's the problem?The Register Security · May 13, 2026
- Windows BitLocker zero-day gives access to protected drives, PoC releasedBleepingComputer · May 13, 2026
- Microsoft, Palo Alto Networks Find Many Vulnerabilities by Using AI on Their Own CodeSecurityWeek · May 13, 2026
- Breaking things to keep them safe with Philippe LaulheretCisco Talos Intelligence · May 13, 2026
- [GUEST DIARY] Tearing apart website fraud to see how it works., (Wed, May 13th)SANS Internet Storm Center · May 13, 2026
- How Rapid7 is bringing Cyber GRC closer to security operationsRapid7 Blog · May 12, 2026
- When "idle" isn't idle: how a Linux kernel optimization became a QUIC bugCloudflare Blog · May 12, 2026
- New TrickMo Variant Uses TON C2 and SOCKS5 to Create Android Network PivotsThe Hacker News · May 12, 2026
- Claude Mythos Finds Only One Curl Vulnerability; Experts Divided on What It Really MeansSecurityWeek · May 12, 2026
- State-sponsored actors, better known as the friends you don’t wantCisco Talos Intelligence · May 12, 2026
- UK water company allowed hackers to lurk undetected for nearly two years, regulator findsThe Record · May 11, 2026
- Your Purple Team Isn't Purple — It's Just Red and Blue in the Same RoomThe Hacker News · May 11, 2026
- The State of Ransomware – Q1 2026Check Point Research · May 11, 2026
- Ollama Out-of-Bounds Read Vulnerability Allows Remote Process Memory LeakThe Hacker News · May 10, 2026
- Friday Squid Blogging: Giant Squid Live in the Waters of Western AustraliaSchneier on Security · May 8, 2026
- Worm rubs out competitor's malware, then takes controlThe Register Security · May 8, 2026
- Why More Analysts Won’t Solve Your SOC’s Alert ProblemBleepingComputer · May 8, 2026
- Why the approaching flood of vulnerabilities changes everything — and what to do about itTenable Blog · May 8, 2026
- When DNSSEC goes wrong: how we responded to the .de TLD outageCloudflare Blog · May 6, 2026
- MuddyWater hackers use Chaos ransomware as a decoy in attacksBleepingComputer · May 6, 2026
- From Stuxnet to ChatGPT: 20 News Events That Shaped CyberDark Reading · May 6, 2026
- Your AI Agents Are Already Inside the Perimeter. Do You Know What They're Doing?The Hacker News · May 6, 2026
- 8×8 updates CX platform with AI, analytics, and frontline management capabilitiesHelp Net Security · May 6, 2026
- ServiceNow strengthens enterprise AI security with Autonomous Security & Risk platformHelp Net Security · May 6, 2026
- Attackers Actively Exploiting Critical Vulnerability in Breeze Cache PluginWordfence Blog · May 5, 2026
- The EOL Blind Spot in Your CVE Feed: What SCA Tools MissBleepingComputer · May 5, 2026
- ShinyHunters claims dump puts 119K Vimeo emails in the wildThe Register Security · May 5, 2026
- The Back Door Attackers Know About — and Most Security Teams Still Haven’t ClosedThe Hacker News · May 5, 2026
- UAT-8302 and its box full of malwareCisco Talos Intelligence · May 5, 2026
- CloudZ RAT potentially steals OTP messages using Pheno pluginCisco Talos Intelligence · May 5, 2026
- ⚡ Weekly Recap: AI-Powered Phishing, Android Spying Tool, Linux Exploit, GitHub RCE & MoreThe Hacker News · May 4, 2026
- How Dark Reading Lifted Off the Launchpad in 2006Dark Reading · May 4, 2026
- ConsentFix v3 attacks target Azure with automated OAuth abuseBleepingComputer · May 2, 2026
- Introducing Dynamic Workflows: durable execution that follows the tenantCloudflare Blog · May 1, 2026
- New infosec products of the month: April 2026Help Net Security · May 1, 2026
- More PayPal emails hijacked to deliver tech support scamsMalwarebytes Labs · Apr 30, 2026
- EtherRAT Distribution Spoofing Administrative Tools via GitHub FacadesThe Hacker News · Apr 30, 2026
- Finance company stores DB credentials in helpfully labeled spreadsheetThe Register Security · Apr 30, 2026
- Finance company stores DB credentials in helpfully labeled spreadsheetThe Register Security · Apr 30, 2026
- New Wave of DPRK Attacks Uses AI-Inserted npm Malware, Fake Firms, and RATsThe Hacker News · Apr 29, 2026
- EU waves through open source age-check tool to keep kids safe onlineThe Register Security · Apr 29, 2026
- What to Look for in an Exposure Management Platform (And What Most of Them Get Wrong)The Hacker News · Apr 29, 2026
- BlueNoroff Uses Fake Zoom Calls to Turn Victims Into Attack LuresDark Reading · Apr 28, 2026
- Feuding Ransomware Groups Leak Each Other's DataDark Reading · Apr 28, 2026