Note: articles are for educational purposes and are not professional security advice — consult an expert for your specific needs.

Signal K path traversal: 2.34.0 fixes secret theft

In short

Signal K resources-provider path traversal can expose the JWT signing secret and enable persistent command execution with server-process privileges. Versions before 2.34.0 are affected; update to 2.34.0 even if anonymous reads are disabled, since read-only users remain exposed. Review saved providers too: updating does not undo earlier configuration changes.

Summary written with AI from this article, and checked against it.

A shield blocks access from a resource folder to a secret key, illustrating the Signal K 2.34.0 path traversal fix.

Affected systems and impact

FlawAffected systemsImpact
Unvalidated resource identifiers allow path traversal outside the storage rootSignal K resources-provider versions before 2.34.0, including authenticated read-only access even with allow_readonly=falseSigning-secret and password-hash theft, file writes and deletion, and persistent command execution with server-process privileges

A read-only Signal K account can use Signal K path traversal to steal the signing secret and reach command execution. That's the finding in GHSA-4xm8-rg9h-jhq2. The flaw lives in resources-provider versions before 2.34.0; 2.34.0 is the patched release. Check your installed version and the allow_readonly setting before you update — disabling anonymous reads alone does not protect authenticated read-only users.

For administrators, the consequence extends beyond an exposed resource file. The advisory describes a chain: read configuration, forge an administrator token, create a command-executing provider, keep it across restarts. Patch exposed instances before routine maintenance because the documented outcome is command execution with the server process's privileges.

Check Signal K access and resources-provider versions

Start with the installed component and its access settings, not the advisory's exploit. Anonymous access and read-only authenticated access are separate exposure paths. A setting that blocks the former does not remove the latter.

  1. Identify the installed resources-provider version, including whether it's bundled with signalk-server or installed standalone. The advisory marks versions before 2.34.0 as affected and 2.34.0 as patched. Its affected-product wording also covers all signalk-server releases, so don't substitute a server release label for checking the resources-provider component. Use your installed-package or deployment records to establish what's actually present.

  2. Check whether allow_readonly=true is enabled. The advisory describes this as a supported, UI-toggleable setting that permits anonymous reads. With allow_readonly=false, the documented traversal request returns 401 to an anonymous caller but still succeeds with a read-only user token. Turning off anonymous reads is a partial access restriction, not a fix.

  3. If you need to inspect how the server classifies an existing token, query its login-status endpoint. Replace the placeholder with a token you already hold and adjust the server address for your authorised instance.

    This Python request prints the existing token's reported userLevel without reading configuration files or creating providers.

    import json
    import urllib.request
    
    server = "http://127.0.0.1:3000"
    existing_token = "REPLACE_WITH_AN_EXISTING_TOKEN"
    
    status_request = urllib.request.Request(
        server + "/skServer/loginStatus",
        headers={"Authorization": "JWT " + existing_token},
    )
    status = json.load(urllib.request.urlopen(status_request))
    print(status["userLevel"])

    This is a privilege check, not a vulnerability detector or version check. An expected result does not establish that the traversal is fixed. Do not use a disclosed signing secret to generate a test token against an operational service.

  4. Update the affected resources-provider component to 2.34.0 and verify which component your deployment actually loads. The advisory does not supply an installation command or deployment-specific upgrade procedure, so follow the update mechanism appropriate to your installation rather than guessing a package command.

Until the update is complete, I'd restrict who can reach the service and disable anonymous reads where they're unnecessary. Those are containment choices; they should not be recorded as remediation of Signal K path traversal while an affected component remains installed.

Signal K at a glance: 2.34.0 is the patched release; Check whether allow_readonly=true is enabled; Turning off anonymous reads is a partial access restriction; Patch exposed instances before routine maintenance

Where the resources path check fails

The documented entry point is GET /signalk/v2/api/resources/:resourceType/:resourceId. The handler passes resourceId to FileStore.getResource() without validation. That storage method constructs a path with path.join(this.resources[type].path, itemUuid), then reads the file and parses its contents as JSON.

The advisory shows that an encoded, multi-level traversal can take that read outside the intended resource directory. The important boundary isn't whether a request names a resource type — it's whether the final filesystem location stays inside that resource type's storage root. In the documented implementation, the supplied identifier defeats that boundary.

The read has a particularly consequential destination: <config>/security.json. Signal K stores its JWT signing secret there in plaintext. The advisory connects the unvalidated resource identifier to disclosure of that secret, rather than treating arbitrary JSON-file access as an isolated information leak.

Its summary also covers file writes and deletion outside the storage root through the resources and applicationData APIs. The demonstrated takeover chain, however, starts with a resource read. That distinction matters when reviewing the recommended fix: protecting only the demonstrated GET handler would leave the other storage operations out of the review.

How Signal K path traversal becomes admin access

The signing secret turns a file-read problem into an authentication problem. The advisory demonstrates an HS256-signed token identifying the user as admin, created using the disclosed secret. Signal K accepts that token at /skServer/loginStatus with userLevel reported as admin, and the advisory says admin-protected endpoints accept it too.

This is why a read-only account is not a reassuring boundary on an affected installation. Its initial permission is sufficient to retrieve material used to create a token with a different privilege level. The documented escalation does not require the attacker to begin with an administrator's existing token.

The next link is POST /skServer/providers, an administrator-protected endpoint that accepts a provider with type Execute. The advisory reports that creating such a provider invokes its command through spawn('sh', ['-c', command]). Command execution happens at provider creation time; the chain does not depend on waiting for a later restart.

A forged token grants access to the existing command-execution functionality. Reviewing only the original read request would miss the privilege change and the resulting provider configuration.

Why a restart does not remove an Execute provider

The advisory reports that the created provider is written to settings.json and survives restarts. It also reports independent local reproduction that included restart persistence. A restart alone is not a cleanup step for the documented provider. The saved configuration is part of the takeover chain.

For an instance that may have been exposed, I would review the configured providers and their saved commands as well as installing the update. An unfamiliar Execute provider deserves investigation because it's the persistence mechanism described in the advisory. The mere presence of that provider type, however, is not proof that someone used this vulnerability.

Keep the review specific. Establish which command-capable providers are expected, which commands they contain, and whether the saved settings match the intended configuration. These are suggested response checks, not evidence that a particular installation has been attacked. Do not remove every command-capable provider simply because the advisory names that feature.

The reported impact is execution with server-process privileges. That's serious enough to require more than a package inventory, but it's also the boundary the advisory establishes. A saved provider should be assessed alongside the affected software, rather than assuming that updating the package explains or reverses every earlier configuration change.

BoundaryAdvisory recommendation
Resource identifiersValidate resourceId against a strict whitelist, such as UUID format, before storage calls, including PUT and DELETE.
Filesystem accessUse path.resolve() in FileStore.getResource/setResource/deleteResource and reject results outside this.resources[type].path.
Signing-secret storageMove the JWT signing secret outside the API-readable configuration directory into a dedicated key file with mode 0600.
Command executionConsider requiring explicit opt-in for command-executing provider types such as Execute.

Storage-layer containment catches path traversal at the filesystem boundary, while request validation catches it at the API handler. The advisory explicitly names both the API handler and the storage methods. For a code review, that means checking where an identifier enters the system and where it finally becomes a filesystem path.

The secret-location and provider recommendations address later stages of the same chain. They are not reasons to leave traversal unfixed. They describe additional boundaries between reading resource data, obtaining signing material, and reaching functionality that executes commands.

What the 2.34.0 advisory does not establish

The advisory identifies a patched version, but it does not provide a release-by-release mapping between signalk-server and its bundled resources-provider. It also gives no version-check command. That limits how specific an installation recipe can be: confirm the component actually deployed instead of inferring its status from an unrelated runtime version or an administrator page.

The report contains a local proof of concept and says reproduction was independently verified. It does not report attacks against operational deployments. That supports taking the demonstrated chain seriously without describing every exposed server as compromised or presenting laboratory reproduction as evidence of exploitation in the wild.

Its demonstrated read returns JSON files through a JSON-parsing storage method. The summary also reports write and delete capabilities, but does not give those paths the same detailed reproduction. Keep those distinctions when communicating scope: neither reduce the issue to a harmless file read nor invent additional techniques beyond the advisory.

I'd treat Signal K path traversal as an urgent patch-and-review task, with two separate completion questions: is the affected component updated, and does the current provider configuration match what the administrator intended? The advisory's persistence finding is the reason not to let a successful upgrade answer both questions automatically.

FAQ

Frequently asked questions

Which environment was used to verify the Signal K issue?

The advisory reports independent reproduction on master commit 340d5bb6 using Node 22 on macOS, including verification that the created provider persisted across a restart.

Can the security.json disclosure expose password information too?

Yes. The advisory says reading the configuration file exposes user password hashes as well as the JWT signing secret. It does not describe those hashes as plaintext passwords.

Source

  1. AdvisoryGHSA-4xm8-rg9h-jhq2 · github.com

How this article was made: drafted with AI from the source above and fact-checked against it, then reviewed by Vishal on . How we write and check articles.

Vishal

About the author

· Software & security engineer

GitHub · LinkedIn · X

Vishal writes Trickyworld's tutorials and interview-preparation guides on programming, databases, cyber security and AI. Vishal has been shipping production software long enough to have firm opinions about Python, PHP, Node.js, and JavaScript, and to have been wrong about each of them at least once. The work has run the whole stack: Drupal and Laravel applications, React front ends, MySQL and MongoDB underneath, Redis and Memcached for the things that had to be fast, Apache Solr for the things that had to be findable. That last part turned out to matter more than anyone expected. Tune a Solr index for a season, then watch a language model confidently retrieve the wrong document, and you recognise an old problem wearing new clothes. Most of what is hard about AI systems is not the model. It is retrieval, caching, latency budgets, and deciding what the system does when the answer comes back wrong — which is work he has been doing since well before anyone called it AI engineering. He plays a lot of games, which is less a hobby disclosure than an admission of where a good share of his engineering instinct came from. Real-time systems with a frame budget. State that has to stay coherent while a player does something no designer anticipated. The permanent question of what happens when the frame cannot finish in time. Those habits carry over more directly than they have any right to. He has written several books on programming, all built on the same conviction: most technical writing is unclear because the author never decided what to leave out. More from Vishal → · Editorial policy

More on Cyber Security.

Cyber Security

PHP2Shell vulnerability: PHP code execution without login

A new PHP flaw nicknamed PHP2Shell lets an attacker take over a server with a single request — no login, no stolen password, no bug in your code required. Here's exactly how CVE-2026-109618 and CVE-2026-109619 work, how to check if you're exposed with a free script, and how to fix it before someone else finds it first.

16 min read

Latest articles

$ subscribe --weekly

Get the next tutorial in your inbox.

Programming, security and AI — the practical bits, no spam. Unsubscribe any time.