User input as CLI argv: MISP → CakePHP path-switch phar RCE, SAP multitenant credential endpoint, and Android exported-activity filename injection¶
Source: GitHub advisory wave published 2026-09-17T18:32–19:05Z (plus a critical updated-feed resurfacing at 19:05Z). A sibling MISP finding (Overmind statistics legend stored XSS) is folded into the Sept 7 MISP page.
This batch is durable because all three entries are the same meta-pattern in different runtimes: user-controlled fields that arrive at a structural sink — a command-line dispatcher, a multitenant metadata endpoint, or an OS file-staging path — where the framework, not the app, does the dangerous interpretation.
What changed¶
| Advisory | Component | Boundary | Operator value |
|---|---|---|---|
| GHSA-2q9g-8hcw-6c23 | MISP (events/contact form → background job dispatch) | Job arguments are passed directly as argv of the CakePHP console process. ShellDispatcher::_parsePaths() scans the entire argv for path switches (-app, --app, -working, --working, -root, --root, -webroot, --webroot) and takes the next element as the application root. The contact endpoint forwards the user-controlled person and message fields into job arguments unvalidated → set person=-app, message=phar://<uploaded archive> → bootstrap includes Config/core.php from the attacker's archive → deterministic unauthenticated RCE as the web user | The reserved-flag-in-argv class: any feature that concatenates user fields into a CLI invocation must be tested against the invoked framework's own option grammar, not the app's. PHAR-deserialization bootstrap includes are the PHP execution leg |
| GHSA-955m-rr6m-2f9v / CVE-2026-76969 | @sap/cds-mtxs (SAP CAP multitenancy library) < 1.18.4, 2.x < 2.7.7, 3.x < 3.9.7, 4.0.1–4.0.2 (critical) | With extensibility enabled, certain mtxs endpoints lack sufficient checks: an unauthenticated attacker sends crafted requests to obtain tenant credentials, then abuses them to replace/delete tenant data (high integrity/availability impact, partial confidentiality) | Multitenant SaaS plumbing libraries expose a tenant-credential API surface that is often outside the app team's threat model. Audit question for any CAP/mtx-style stack: which endpoints mint or return per-tenant service credentials, and what authenticates them? |
| GHSA-x3gc-cx3q-fw5m | Verizon Cloud for Android (com.vcast.mediamanager) < 26.7.10 (medium) | Exported activities OneTouchUploadActivity / PrintShopCloudActivity accept ACTION_SEND(_MULTIPLE) intents; the file-staging sink concatenates the intent-supplied _display_name without sanitization → path traversal out of the staging dir, arbitrary file write → attacker-controlled content injected into the authenticated user's cloud account with no user interaction | Android co-resident-app attack surface: exported activity + Intent-extras filename = classic unsanitized-filename file-write sink, reachable by any installed app without permissions. Mobile-recon heuristic: enumerate exported components (dumpsys package / aapt dump xmltree) and fuzz filename-ish extras (_display_name, title, name) with ../ markers |
Operator validation patterns¶
1. Framework-option injection in delegated argv (MISP pattern)¶
- Find every sink where app code spawns a console/CLI process with fields that include user input (job queues, export jobs, report generators, webhook relays).
- Do not test for shell metacharacters — the spawn is usually array-based (
execve, no shell). Test the invoked framework's option grammar instead: for CakePHP consoles send-app/--app/-root/-webrootin one field and a controlled path/URI in the neighbor field; for other frameworks enumerate their dispatcher's switches the same way. - PHP targets: pair a path-switch with a
phar://pointer at an archive you can upload somewhere on the host (avatar/attachment fields are common); the execution leg is the bootstrapincludeof a config file inside the archive. Non-PHP targets: pair the switch with any file-read/import sink the CLI supports. - Proof discipline: lab MISP/CakePHP only, synthetic archive with an inert marker in
Config/core.php, and confirm at import time (log/marker), not on shared tenants. Never drop real PHP shells on engagements — stop at the include-triggered marker.
2. Tenant-credential endpoint sweep (SAP cds-mtxs pattern)¶
- On any multitenant platform with an extension/tenancy sidecar library (CAP mtxs, multi-tenant OAuth bridges, extensibility services): enumerate routes that mention
tenant,subscribe,credentials,extension,boundand test them unauthenticated and with cross-tenant tenant IDs. - The reportable finding is credential issuance/return to an unauthorized caller; stop before using any obtained credential against other tenants' data (replace/delete is out of bounds outside an approved lab).
- Version fingerprinting matters here: the library version is often reflected in response headers or error shapes of
/mtxroutes — a cheap recon signal that the app runs an unpatched train.
3. Exported-component filename fuzz (Android pattern)¶
- Static recon: list exported activities/providers; flag any handling
ACTION_SEND*(share targets) since they accept extras from arbitrary apps by design. - Dynamic proof with two test apps you control (or
adb shell am startas the co-app proxy): sendACTION_SENDwithClipData+_display_name=../../markerand confirm the write lands outside the staging dir using a synthetic marker file in a world-readable location. - Impact framing for reports: co-resident malicious app → arbitrary write into the target app's storage → content injection into the victim's cloud account without user interaction; do not demo against real user accounts.
Durable operator value¶
- argv is a parser target, not just a string sink. Array-exec eliminates shell injection but leaves the program's own flag grammar exposed. Audit = read the dispatcher's option table, then test each reserved switch against neighbor-field control.
- Three runtimes, one shape: framework dispatcher (CakePHP), tenancy library (cds-mtxs), and OS intent delivery (Android exported activity) all trusted an upstream field that the platform interprets structurally. Wherever the platform interprets, the app's validation vocabulary is the wrong vocabulary.
- PHAR-in-bootstrap is still the PHP RCE leg for "path switch + uploadable archive" primitives — treat any attacker-influenced "application root" as a code-execution candidate, not a read primitive.
Safety¶
- Authorized lab instances only for the MISP/CakePHP and CAP proofs; inert archive markers, synthetic tenant IDs, no real tenant credentials captured or replayed.
- Android testing on your own device profile with your own test app and marker files; never target another user's account or install surveillance payloads.
- Keep credentials, tenant identifiers, and device data out of wiki and report evidence.
September 22 follow-up: MISP ships the phar wrapper with zero legitimate use (wrapper-audit rule)¶
- CVE-2026-95806 / GHSA-8rgx-3gvf-26gg (high): MISP registers PHP's phar stream wrapper in both its web and console entry points, yet no MISP/CakePHP/runtime code ever reads or constructs phar archives. Consequences: any filesystem operation on a caller-influenced path that resolves to an uploaded
.phartriggers implicitunserialize()(deserialization sink), and a relocated app root (see the-appargv leg above) can reach executable code inside an uploaded phar. Operator rule generalized from this advisory: on any PHP target, treat wrapper availability as attack surface inventory — probe whetherphar://is accepted at file-existence/read/unlink sinks (file_exists('phar://…')timing/popcheck shapes), and in source audits, flag registered wrappers with no legitimate consumer; a wrapper nothing uses is a primitive only an attacker uses. Combine with the two legs already on this page (argv path switch + upload) for the full chain — prove only in a lab instance with an inert archive marker.
October 7 follow-up: site-admin settings turn MISP workers into a client of attacker Redis (CVE-2026-106513 / GHSA-j4wg-24xp-wq96)¶
MISP exposes its Redis host addresses (core app, ZeroMQ plugin, SimpleBackgroundJobs plugin) through the web UI/API to site-admin users, and the background-job workers trust raw Redis job payloads with no validation. A hijacked site-admin session (e.g. via stored XSS) can repoint the Redis host setting at an attacker-controlled Redis server, restart the workers, then inject job payloads the workers execute → arbitrary command execution as the worker account. The same interface also flipped download_attachments_on_load back on for follow-on client-side attacks.
- Durable axis: configurable connection targets in admin UIs are SSRF/RCE legs whenever a worker/service later dials them. The admin setting itself looks benign (it only stores a host), so route-audits that only trace request-time fetchers miss it. Audit rule for any job-queue/middleware product (Redis, RabbitMQ, Kafka broker fields, webhook hosts, SMTP relays stored in tenant config): trace which daemon dials the stored target later, and whether the protocol on that leg carries executable semantics (job payloads, pickle/JSON-deserializing consumers, plugin-loading brokers). A Redis server the workers will connect to is a code-execution endpoint.
- Second reusable idea: settings-inventory as post-compromise primitive list. After obtaining any low/mid-tier admin session on a self-hosted platform, enumerate writable settings that name a network destination or a client behavior toggle (attachment auto-load, auto-redirect, external fetch) — the pivot chain is setting-write → service-dials-attacker → payload-executes, not just data read. Prove only on a lab MISP with an owned Redis listener and an inert job payload marker; never against shared threat-sharing instances.
October 7 follow-up (16:1xZ): forced-TOTP guard only understands browser redirects — every machine request shape walks past it (CVE-2026-107180 / GHSA-jgf2-xf9x-w72j, high, fixed 2.5.48)¶
On MISP instances with Security.otp_required, the mandatory-TOTP-enrolment guard was implemented for standard browser requests only: enforcement worked by redirecting the user to the enrolment page, and every non-browser request shape — AJAX/XHR, REST API, .json format suffixes, restSearch, automation calls — cannot follow that redirect, so the guard skipped the check entirely. An authenticated user who never enrolled could operate with full instance access indefinitely through machine-shaped requests. The first fix added an AJAX-specific guard; the second broadened it to every non-browser shape while preserving the API-key (logged_by_authkey) exemption.
Durable rule, generalizes past MISP: any security gate implemented as a browser redirect is bypassed by declaring a non-browser request shape — X-Requested-With: XMLHttpRequest, Accept: application/json, format-suffix routes, GraphQL, API tokens. For every forced-flow control a product implements (mandatory 2FA enrolment, password change, EULA, consent, onboarding), build a request-shape matrix: browser GET vs XHR vs JSON-suffix vs REST endpoint, same session cookie, and diff enforcement. Second leg of the rule: the fix history is the test plan — first-fix-covers-one-shape (AJAX), second-fix-covers-all-shapes is the canonical drift; when re-testing a "fixed" forced-flow guard, lead with the shapes the first fix didn't name.
Sources: GHSA-2q9g-8hcw-6c23 · GHSA-955m-rr6m-2f9v · CVE-2026-76969 · SAP note 3798315 · GHSA-x3gc-cx3q-fw5m · GHSA-8rgx-3gvf-26gg · GHSA-j4wg-24xp-wq96 · GHSA-jgf2-xf9x-w72j