Search: 2.9.99.5
317 threats
Most recently published first
| Severity | CVSS | Signals | Threat | Source | Published | Score and star |
|---|---|---|---|---|---|---|
| Malicious | – | MaliciousGCVE Database --- _-= Per source details. Do not edit below this line.=-_ ## Source: amazon-inspector (6c8ce91cbe1aaa587613795b1b82cc84384b499a29af4a18c0a820b77ea1d834) The npm package ach-detail@99.0.1 ships a preinstall lifecycle script (scripts/preinstall.js) that runs automatically on `npm install`. The script collects the installer's hostname, package name and version, Node.js version, platform, timestamp, and a nonce, and POSTs the payload to a hardcoded remote endpoint at https://callback.kuldeep.io/beacon, with an HTTP fallback to the same host. The package is published to the public npm registry at version 99.0.1 — a version-inflation pattern consistent with dependency-confusion targeting of a private internal package of the same name. A log string in the script self-labels the behavior as an authorized bug-bounty PoC, but that label is author-controlled, does not change the observable behavior, and does not represent consent from any installer that resolves the package (accidentally or through dependency-confusion). Installer-side host identifiers leave the machine to a non-first-party endpoint on install. | GCVE Database | |||
| Malicious | – | MaliciousGCVE Database The npm package 'clover-codelab-remote-pay-cloud' version 99.9.9 is a malicious package designed to exfiltrate system information during installation. It runs a postinstall script that collects OS username, current working directory, hostname, and non-internal IPv4 address, then sends this data to a hardcoded external URL. The package mimics the name of a legitimate Clover SDK to exploit dependency confusion but provides no legitimate functionality. | GCVE Database | |||
| Malicious | – | MaliciousGCVE Database --- _-= Per source details. Do not edit below this line.=-_ ## Source: amazon-inspector (6b9fb0d73b7d26454a227e93754f11ff2405424b1279490863055e8d8c8c6498) Package targets the electrode-io internal name `electrode-ota-ui-app` with an inflated 99.0.1 version to win dependency resolution against a private registry. package.json declares both `main: index.js` and `scripts.postinstall: node index.js`, so on `npm install` and on any `require()` the package unconditionally runs `collectAndSend()` in index.js. That function gathers host identifiers via `os.hostname()`, `os.userInfo()`, `os.platform()`, and `os.release()`, resolves the installer's public IP via ipify and geo/ISP data via ipapi.co, and POSTs a JSON payload to the hardcoded Burp Collaborator subdomain `https://itfv50wbocctx0j32fyfq8z7uy0ptdn1c.oastify.com/callback`, controlled by the package author. README self-labels as a dependency-confusion PoC, but the callback is live and any installer whose resolver picks this public package over the intended internal one is compromised. | GCVE Database | |||
| Malicious | – | MaliciousGCVE Database The npm package com.db.dbk.ui-forms versions 99.0.0 and 99.0.1 contains malicious code that executes automatically during installation. It collects sensitive host information and environment variables potentially containing secrets, then exfiltrates this data to a hardcoded external server. The package is described as a 'dependency confusion proof of concept' but performs unauthorized data exfiltration regardless. | GCVE Database | |||
| Malicious | – | MaliciousGCVE Database --- _-= Per source details. Do not edit below this line.=-_ ## Source: amazon-inspector (3bc8cd463940a0fe70eee979bd85b9ea41eed627f30cf96be8e0174c9106c7e1) The package presents itself as an audit rule pack but ships a credential harvester in index.js. Its exported postScan routine copies ~/.sui/sui.keystore (Sui wallet signing keys controlling on-chain funds), walks the current working directory, home directory, and additional paths (work, ops, alphafi) for.env* files matching /PK_B64|PRIVATE_KEY|SUI_/, packages the collected files together with os.hostname() and os.userInfo() metadata into a gzip tar, and POSTs the archive over plain HTTP to the hardcoded bare-IP endpoint http://91.92.241.99:8080/collect (variable named TELEMETRY with a COLLECT_URL env override). Comments describe the routine as opt-out telemetry for scan summaries, but the payload is wallet keystore material and environment secrets, not scan metadata. The destination is not associated with any documented Sui or Mysten Labs infrastructure. ## Source: ghsa-malware (463bbc5e417bf04a6676179a7de62ade021d8bf7167d6b603ee02cf5e30d1ace) Any computer that has this package installed or running should be considered fully compromised. All secrets and keys stored on that computer should be rotated immediately from a different computer. The package should be removed, but as full control of the computer may have been given to an outside entity, there is no guarantee that removing the package will remove all malicious software resulting from installing it. | GCVE Database | |||
| Malicious | – | MaliciousGCVE Database The npm package warp-drive-internal-tooling version 99.9.9 contains malicious code that executes a hidden PowerShell process during installation. This process downloads and runs an unverified binary named Verification_Tool.exe from an anonymous file hosting service, resulting in unattended execution of attacker-controlled code on Windows machines. The behavior is consistent with a dropper designed to conceal its activity. | GCVE Database | |||
| Malicious | – | MaliciousGCVE Database --- _-= Per source details. Do not edit below this line.=-_ ## Source: amazon-inspector (e6144be61d70f258741e5d4cc1476021f93e3ce82ffa00a3f86189537a1438a6) The package's `tt-help watchdog` subcommand starts a long-running agent that POSTs heartbeats to a remote server (default hardcoded to http://117.71.53.99:17301, referenced in src/lib/constants.js and the README/run-explore examples) and executes commands returned in the response. In WatchdogAgent, syncCommands maps entries from the server's `commands` array into child_process.spawn(command, { shell: true }) via ProcessManager.startCommand, with auto-restart — the remote operator selects arbitrary shell commands to run on the installer's host. Each heartbeat body assembled by _buildHeartbeatBody carries hostname, non-internal IPv4 address, OS platform/release/arch, CPU count, memory, node version, uptime, load average, and the contents of ~/.tt-help.json (server, proxy, browser, userId, tuning fields), POSTed as JSON to ${serverUrl}/api/watchdog/heartbeat at the configured interval (default 15s). In addition, _startUpgradeChecker polls the npm registry every 10 minutes and, when a new version of tt-help-cli-ycl is published, invokes `npm install -g tt-help-cli-ycl@latest` via child_process.exec and re-spawns, so the publisher can push arbitrary new code to every running agent host without user confirmation. The combination of remote-command execution, ongoing host inventory + stored-config exfiltration to a bare-IP destination, and unattended auto-upgrade constitutes a full command-and-control backdoor rather than a legitimate remote-management tool. | GCVE Database | |||
| Medium | 5.4 | EPSS 0.4% | CVE-2026-54707Onionshare cli · OnionShare Receive mode writes uploaded files even when file uploads are disabled Medium5.4EPSS 0.4%GCVE DatabaseCVE-2026-54707 ### Summary OnionShare CLI/Desktop 2.6.3 does not enforce the Receive mode `disable_files` setting at the file upload sink. When a Receive service is configured as a text-message-only endpoint (`--disable-files` / "Disable uploading files"), a remote sender who can reach the OnionShare service can still send a crafted multipart request containing `file[]`; OnionShare writes the uploaded bytes to disk before the route handler skips file accounting. This affects the shipped `onionshare-cli` Python package and the desktop application because both use the same `onionshare_cli.web.receive_mode` request-streaming implementation. ### Details Tested repository: `https://github.com/onionshare/onionshare` at commit `8cc75e1d7e88bd31f7276733449d412bf71c8999`. Affected product evidence: - `cli/pyproject.toml` declares `onionshare_cli` version `2.6.3`. - `desktop/pyproject.toml` declares `onionshare` version `2.6.3` and depends on `onionshare_cli` from `../cli`. - `cli/setup.py` publishes `onionshare-cli` and includes `onionshare_cli.web` plus templates/static resources. - `desktop/setup.py` publishes `onionshare` and exposes both `onionshare` and `onionshare-cli` console scripts. Reachable default/common paths: - CLI Receive mode is exposed through `--receive` (`cli/onionshare_cli/__init__.py:55-57`). - The `--disable-files` option is documented and stored in mode settings (`cli/onionshare_cli/__init__.py:156-160`, `cli/onionshare_cli/__init__.py:254-261`). - Desktop Receive mode exposes the same setting via the "Disable uploading files" checkbox and stores it as `receive.disable_files` (`desktop/onionshare/tab/mode/receive_mode/__init__.py:89-99`, `desktop/onionshare/tab/mode/receive_mode/__init__.py:246-254`). - User documentation says "Disable uploading files" should "only allow submitting text messages, like for an anonymous contact form" (`docs/source/features.rst:64`). - Advanced documentation lists `--disable-files` and `disable_files` as the option to disable receiving files (`docs/source/advanced.rst:162-163`, `docs/source/advanced.rst:455`). Root cause: - The Receive template hides the file input when `disable_files` is set (`cli/onionshare_cli/resources/templates/receive.html:51-56`), but this is only UI-side. - The `/upload` route skips `request.files.getlist("file[]")` and file accounting when `disable_files` is enabled (`cli/onionshare_cli/web/receive_mode.py:96-135`). However, by this point Werkzeug has already parsed the multipart body and invoked the custom stream factory. - `ReceiveModeRequest.__init__()` treats every `POST /upload` or `POST /upload-ajax` as an upload request and creates a receive directory regardless of `disable_files` (`cli/onionshare_cli/web/receive_mode.py:369-391`). - `ReceiveModeRequest._get_file_stream()` creates a writable `ReceiveModeFile` for each uploaded part without checking `self.web.settings.get("receive", "disable_files")` (`cli/onionshare_cli/web/receive_mode.py:517-540`). - `ReceiveModeFile` opens `<receive_mode_dir>/<secure_filename>.part`, writes attacker-controlled bytes, then renames the `.part` file to the final filename (`cli/onionshare_cli/web/receive_mode.py:272-285`, `cli/onionshare_cli/web/receive_mode.py:320-346`). False-positive screening performed: - `secure_filename()` is used at `cli/onionshare_cli/web/receive_mode.py:111-113` and `cli/onionshare_cli/web/receive_mode.py:527-528`, so the confirmed issue is not path traversal; the file is written under the configured receive data directory. - The UI hiding the file input is bypassable by direct multipart POST. - Route-level `if not disable_files` only affects later accounting/status/webhook behavior; it does not prevent the stream sink from creating and writing the file. - Default non-public onion services require the sender to know the onion address and private key unless the user opts into public mode. This limits exposure but does not enforce the user-selected "text only" security policy for authorized senders or public contact-form deployments. - A control case with `disable_text=True` showed submitted text was not written as a message file, demonstrating the harness was exercising the settings boundary. Affected versions / patched versions: - Affected versions: unknown; confirmed in version `2.6.3` at commit `8cc75e1d7e88bd31f7276733449d412bf71c8999`. Earlier versions were not tested during this audit. - Patched versions: 2.6.4 Severity: Rationale: `AV:N` because the Receive endpoint is reached over the OnionShare HTTP service; `AC:L` because a crafted multipart POST is straightforward once the service is reachable; `PR:L` because the sender generally needs the OnionShare URL/private key unless the receiver intentionally runs public mode; `UI:N` because no further receiver interaction is required after service startup; `S:U` because the same local application writes the file; `C:N` because this PoC does not read data; `I:L` because the attacker writes unwanted files in a mode configured to | GCVE Database | ||
| Medium | 4.2 | Medium4.2GCVE Database ### Summary A template injection vulnerability in the `create_workflow_for_notification` tool lets a caller embed Jinja2 expressions that the Dynatrace workflow engine evaluates at runtime, exfiltrating event data to attacker-controlled destinations through a workflow that persists in the tenant after the MCP session ends. ### Details The `create_workflow_for_notification` tool interpolates three caller-supplied parameters (`teamName`, `problemType`, `channel`) directly into a Dynatrace Workflow definition. Dynatrace Workflows use Jinja2 templating: per the [official documentation](https://docs.dynatrace.com/docs/analyze-explore-automate/workflows/reference), `{{ ... }}` expressions in action inputs are evaluated at workflow runtime for every action except `Run Javascript` (which is carved out specifically to avoid code injection). A caller can therefore supply, for example, `teamName = "{{ event() }}"` and have the workflow engine evaluate that expression at runtime, serialising the full event object into the message body delivered to the Slack channel. The vulnerable code is in `src/capabilities/create-workflow-for-problem-notification.ts`, lines 82-99: ```typescript let notificationWorkflow: WorkflowCreate = { title: `[MCP POC] Notify team ${teamName} on problem of type ${problemType}`, description: `Automatically created workflow to notify team ${teamName} on problems of type ${problemType} - ...`, isPrivate: isPrivate, type: 'SIMPLE', tasks: { send_notification: { name: 'Send notification', action: 'dynatrace.slack:slack-send-message', description: 'Sends a notification to a Slack channel', input: { connectionId: 'slack-connection-id', channel: `{{ \"${channel}\" }}`, // <-- channel sits inside {{ }} message: `🚨 Alert for Team ${teamName}\n*Problem Type*: ${problemType}\n` + `*Problem ID*: {{ event()["display_id"] }}\n*Status*: {{ event()["event.status"] }}\n` + `<{{ environment().url }}/ui/apps/.../problem/{{ event()["event.id"] }}|Click here>`, }, active: true, }, }, }; ``` The action used is `dynatrace.slack:slack-send-message`, which is not in the documented Jinja-expression exception list. Its inputs are evaluated at workflow runtime. The schema in `src/index.ts:1052-1070` registers `teamName`, `problemType`, and `channel` as `z.string().optional()` with no pattern validation. The `isPrivate` parameter has `.default(false)`, so created workflows are visible tenant-wide unless the caller explicitly sets it. The approval prompt at `src/index.ts:1069-1072`: ```typescript const approved = await requestHumanApproval( `Create a workflow for notifying team ${teamName} via ${channel} about ${problemType} problems`, ); ``` Renders `{{ event() }}` literally to the operator with no indication that it will be templated, and does not surface the workflow's visibility. The workflow is persistent: it remains in the tenant after the MCP session ends, after the operator's MCP credentials are revoked, and after the MCP server is uninstalled. It fires on every matching problem until manually deleted from the Workflows app. The `channel` parameter is uniquely dangerous because it is interpolated inside an existing `{{ "..." }}` expression context - close the string with `"` and you can run arbitrary Jinja expressions in the destination field itself. ### PoC Tested end-to-end against a real Dynatrace tenant. The MCP server was run in stdio mode with the operator's Platform Token. A `tools/call create_workflow_for_notification` was sent with: ```json { "teamName": "{{ event() }}", "problemType": "ERROR", "channel": "#mcp-sec-poc", "isPrivate": true } ``` The operator approved the prompt (which read: `"Create a workflow for notifying team {{ event() }} via #mcp-sec-poc about ERROR problems"`). The MCP returned a workflow ID. Fetching the stored workflow body via the Dynatrace Automation API (`GET /platform/automation/v1/workflows/<id>`) showed the injected expression stored verbatim: ``` title: "[MCP POC] Notify team {{ event() }} on problem of type ERROR" message: "🚨 Alert for Team {{ event() }}\n*Problem Type*: ERROR\n*Problem ID*: {{ event()[\"display_id\"] }}\n..." channel: '{{ "#mcp-sec-poc" }}' action: "dynatrace.slack:slack-send-message" ``` The workflow was then triggered manually via the "Run workflow" feature in the Dynatrace Workflows app, with a synthetic event payload `{"display_id":"P-123","event.status":"OPEN","event.id":"abc-123"}`. The execution log for the `send_notification` task shows the workflow engine evaluated the injected expressions at runtime. The "Input" tab for the executed action contains: ``` channel: #mcp-sec-poc message: Alert for Team {'display_id': 'P-123', 'event.status': 'OPEN', 'event.id': 'abc-123'} *Problem Type*: ERROR *Problem ID*: P-123 *Status*: OPEN <ht | GCVE Database | |||
| Malicious | – | MaliciousGCVE Database The npm package 'ethe' version 99.15.0 contains malicious code that fully compromises any computer on which it is installed or running. The compromise includes potential unauthorized control over the system and exposure of all stored secrets and keys. Immediate removal of the package is advised, but removal alone may not eliminate all malicious components. Secrets and keys should be rotated from a different, uncompromised machine to prevent further damage. | GCVE Database | |||
| –Not rated | – | Tenable Research As federal enforcement tightens and states begin stepping in with their own cybersecurity mandates, water and wastewater utilities face a looming wave of hard compliance deadlines, compounded by recent cyber attacks on state water utilities. Key takeaways While the EPA’s national sanitary-survey mandate stalled in court, the agency is aggressively using existing authority, technical guidance, and enforcement alerts to inspect cyber gaps. Community water systems serving 3,301 to 49,999 people, the vast majority of U.S. systems, must certify their Risk and Resilience Assessments (RRAs) by June 30, 2026, under AWIA 2013. New York has already finalized binding cybersecurity regulations for wastewater facilities, setting a regulatory template that other states are expected to follow in 2026 and 2027. Under CIRCIA, utilities will soon be legally required to report significant cyber incidents to CISA within 72 hours and ransom payments within 24 hours. Federal grant programs (SLCGP) and liability protections have been extended through Sept. 30, 2026, but remain tied to unpredictable budget cycles while targeted cyber threats continue to rise. Navigating the new reality of water cyber regulation In 2023, the U.S. EPA made an initial push to fold cybersecurity evaluations into state sanitary surveys. While that effort was stayed in court and subsequently withdrawn, the underlying federal statutory requirements and enforcement drivers remain fully active. Instead of relying on new survey rules, federal and state regulators are actively using existing statutory authority and technical guidance to shift water cybersecurity from voluntary recommendations to enforceable compliance deadlines. The urgency to strengthen cybersecurity for water facilities is underscored by a recent coordinated cyber attack that disrupted water and wastewater utility operations across more than 30 Minnesota communities in late July 2026. Utility cyber regulations and mandates moving forward America’s Water Infrastructure Act (AWIA) 2013 / Safe Drinking Water Act (SDWA) 1433 is still very much in force. Community water systems serving more than 3,300 people are legally required to certify a Risk and Resilience Assessment (RRA) and Emergency Response Plan (ERP) to EPA on a five-year recertification cycle, and that cycle explicitly covers cyber threats, not just physical and natural hazards. Recertification deadlines: Systems serving 100,000-plus people: March 31, 2025 50,000–99,999 tier: Dec. 31, 2025 3,301–49,999 tier, the vast majority of U.S. water systems: June 30, 2026, with ERPs due six months after. The EPA hasn’t stopped pushing on cyber. It’s just doing it through guidance, technical assistance, and enforcement of existing authority rather than new rulemaking. In May 2024, the EPA issued an enforcement alert warning it would step up inspections tied to cybersecurity gaps found in drinking water systems. On Oct. 23, 2025, the EPA released an updated package of cyber tools: Revised Emergency Response Plan guide Cybersecurity Incident Response Plan (CIRP) template Incident-specific checklists Cybersecurity procurement checklist These tools are designed to help utilities fold cybersecurity directly into the RRA/ERP process they’re already required to complete. States are stepping in where EPA stepped back With the EPA’s national sanitary-survey mandate dead, states have started writing their own cybersecurity rules for water systems. New York is the clearest example: In March 2026, the New York State Department of Environmental Conservation finalized amendments to six New York Codes, Rules and Regulations (NYCRR) Parts 616, 650 and 750 , adding binding cybersecurity regulations for wastewater treatment facilities, including mandatory incident reporting and access-control requirements built around EPA’s own cybersecurity guidance, incorporated into the rule by reference. Reporting requirements took effect March 26, 2026. It’s a template other states are watchi… | Tenable Research | |||
| Malicious | – | MaliciousGCVE Database --- _-= Per source details. Do not edit below this line.=-_ ## Source: amazon-inspector (1dcfb8ede925ca9e0cf7574c2ba3f81ced56682ef6c54439cc00ad5fc5b960fd) The package's preinstall lifecycle script runs automatically on `npm install`. It reads the installer's username (from USER/USERNAME environment variables) and the machine hostname (via os.hostname()), then embeds those identifiers along with the package name and a timestamp into both a DNS lookup and an HTTPS GET request directed at a hardcoded Burp Collaborator subdomain, 4otph6fase1x2won0hrfzul2wt2qqge5.oastify.com. The package name and scope (@wbnr) and its self-description indicate a dependency-confusion payload targeting an internal organization scope; any environment that resolves @wbnr/design from public npm will leak installer host identifiers to the attacker-controlled out-of-band endpoint. The 'harmless bug bounty PoC' framing in the package description does not change the observable behavior: installer-owned identifiers leave the machine to a third-party OOB collector on install. ## Source: ossf-package-analysis (dbd908eecacbb587e9534c244be33296e6fa11092200cba8428351bb66afe844) The OpenSSF Package Analysis project identified '@wbnr/design' @ 99.3.0 (npm) as malicious. It is considered malicious because: - The package communicates with a domain associated with malicious activity. | GCVE Database | |||
| Malicious | – | MaliciousGCVE Database The phabricator-client package on PyPI versions 99.0.0 through 99.0.4 contains malicious code that exfiltrates basic host information such as IP address and username. The package overrides the install command in setup.py to execute this malicious code during installation. The package has no legitimate purpose beyond this data exfiltration. | GCVE Database | |||
| Medium | 6.8 | EPSS 0.4% | CVE-2026-46678pydantic-ai · Server-Side Request Forgery (SSRF) Medium6.8EPSS 0.4%CVE Database V5CVE-2026-46678 ## Summary When an application using Pydantic AI opts a URL into `force_download='allow-local'` (which disables the default block on private/internal IPs), the cloud-metadata blocklist could be bypassed by encoding the metadata IP in an IPv6 transition form (IPv4-mapped IPv6, 6to4, or NAT64). Dual-stack and translated networks route the IPv6 wrapper to the underlying IPv4 endpoint, exposing cloud IAM short-term credentials. This is an incomplete fix of [GHSA-2jrp-274c-jhv3](https://github.com/pydantic/pydantic-ai/security/advisories/GHSA-2jrp-274c-jhv3) / [CVE-2026-25580](https://nvd.nist.gov/vuln/detail/CVE-2026-25580). The parent advisory's remediation guaranteed that "cloud metadata endpoints are always blocked, even with `allow-local`." That guarantee did not hold for IPv6-encoded forms of the metadata IPs. ## Severity Same impact metrics as the parent CVE, but materially narrower attack surface (AC:H instead of AC:L), because exploitation requires the application to have opted into `allow-local` on a URL influenced by untrusted input. ## Who Is Affected Applications are affected **only if** they explicitly opt for `FileUrl` (`ImageUrl`, `AudioUrl`, `VideoUrl`, `DocumentUrl`) into `force_download='allow-local'` on a URL that is, or could be, influenced by untrusted input. Applications are **not** affected if they use any of the bundled integrations to ingest user input, because they do not propagate `force_download` from external data: - `Agent.to_web` / `clai web` - `VercelAIAdapter` - `AGUIAdapter` / `Agent.to_ag_ui` Applications that only download from developer-controlled URLs are not affected. ## Remediation Upgrade to `1.99.0` or later. The cloud-metadata and private-IP blocklists now apply to IPv6 transition forms that route to a blocked IPv4 endpoint (IPv4-mapped IPv6, 6to4, and NAT64 well-known prefix). The blocklists have also been extended to cover additional IANA-reserved IPv4 and IPv6 special-purpose ranges. ## Workaround for Unpatched Versions Avoid passing `force_download='allow-local'` on any URL that could be influenced by untrusted input. If developers must, resolve the hostname themselves and validate the result against their own metadata blocklist — including IPv6-encoded forms — before constructing the `FileUrl`. ## Credits Reported by [j0hndo](mailto:dohyun4466@gmail.com). | CVE Database V5 | ||
| Malicious | – | MaliciousGCVE Database The npm package '@mypwn/hawkeye' version 99.0.0 has been identified as malicious by the OpenSSF Package Analysis project. The package executes one or more commands associated with malicious behavior, making it a security threat to users who install or run this specific version. | GCVE Database | |||
| Critical | 9.0 | Critical9.0GCVE Database ### Summary Budibase's OIDC SSO login links an incoming SSO identity to an existing Budibase account **by email address alone**, without ever checking the `email_verified` claim of the OIDC ID token. Budibase first tries to match the IdP `sub`; when that misses (any fresh attacker IdP account) it silently falls back to matching by the `email` claim and **merges into the existing account by email**, preserving that account's `_id` and roles. Because the `email_verified` flag is never read, an attacker who can make a **configured/trusted** IdP emit a token carrying `email = <victim>` with `email_verified = false` is logged into Budibase **as the victim**, inheriting the victim's roles (including global admin/builder). Per OIDC Core §5.7 the `email` claim MUST NOT be used as an identity key unless `email_verified` is `true`; Budibase effectively delegates all account-linking trust to every configured IdP's email-verification policy while checking nothing itself. Full account takeover of any existing Budibase user, including the instance owner. ### Details The OIDC verify callback extracts the email and never consults `email_verified`: - `packages/backend-core/src/middleware/passport/sso/oidc.ts:59` — `email: getEmail(profile, jwtClaims)`. - `getEmail` (`oidc.ts:113-135`) returns `profile._json.email` ->`jwtClaims.email` -> `preferred_username`. **No `email_verified` check.** - `buildJwtClaims` (`oidc.ts:99-107`) assembles claims from `_json.email`/`emails[0].value` — no verification flag is read. `grep -r email_verified packages/` -> 0 hits. The email is then used as the **account-linking key**: - `sso.authenticate(...)` -> `packages/backend-core/src/middleware/passport/sso/sso.ts`: - `:38,44` `users.getById(generateGlobalUserID(details.userId))` keyed on the IdP `sub`; for a fresh attacker IdP account this 404s and is swallowed (`:45-54`). - `:57-59` **fallback:** `dbUser = await users.getGlobalUserByEmail(details.email)` -> loads the **victim's** account (victim `_id` + roles) purely by email (`packages/backend-core/src/users/users.ts:100-124`, `USER_BY_EMAIL` view, no binding to the IdP `sub`). - `syncUser(...)` (`sso.ts:80,102-138`) spreads `...user`, preserving the victim `_id`/`tenantId`/`roles`; only overwrites provider fields. - `UserDB.save` (`packages/backend-core/src/users/db.ts:235`): because `ssoUser._id` is the victim's, the `_id` branch runs (`:253`), `getById(_id)` matches the victim (`:256`), the "Email address cannot be changed" guard (`:257-259`) does not fire (`dbUser.email === email`), and the `EmailUnavailableError` guard (`:269-275`) is skipped (it only runs in the `!dbUser` branch). The merge proceeds silently; a session JWT is issued for the victim. Per OIDC Core §5.7, the `email` claim MUST NOT be used as an identity key unless `email_verified` is `true`. Budibase never reads the flag. **Preconditions (attack requirement — `AT:P`):** the attacker must be able to authenticate through an IdP that the Budibase instance **trusts** AND get that IdP to assert the victim's email with `email_verified = false`. This is reachable, not exotic: - **Self-registration with an unverified email — Keycloak and Authentik ship with *"Verify Email" OFF by default*; if the trusted IdP allows public sign-up, the attacker registers a new account and simply enters `email = <victim>` at sign-up. No confirmation email is needed — the IdP stores and asserts it unverified.** - **Self-service profile editing** — many IdPs let a logged-in user change their own email without forced re-verification. - **Attacker-operated / federated IdP or permissive social login** — where the attacker controls or influences a trusted provider, or the provider asserts a user-typed (unverified) email. It is **not** exploitable through a strict corporate IdP that enforces email verification (there `email_verified = true` and the attacker cannot claim the victim's address) — which is exactly why Budibase must check the flag rather than assume every configured IdP enforces it. The defect is unconditional on the Budibase side; the attack requirement is purely the (default, common) IdP email policy. ### PoC Reproduced live on Budibase `3.39.14` (self-hosted, community license) against a stock **Keycloak 26** realm `budi` with default "Verify Email" = off; OIDC client registered and activated in Budibase. **Setup:** a pre-existing **victim** global-admin Budibase account `victim@stand.local` (`_id = us_1ab2dfcf…`, local account, *no IdP link*). The attacker owns their **own** IdP account (`attacker`, distinct `sub`) and can set its email attribute unverified. **Step 1 — the IdP asserts the claim (proves `email_verified=false`):** ``` POST /realms/budi/protocol/openid-connect/token (Keycloak) grant_type=password&client_id=budibase&client_secret=…&username=attacker&password=Attacker123!&scope=openid email profile -> id_token payload: { "sub":"3cf58c45-…", "preferred_username":"attacker", "email":"victim@s | GCVE Database | |||
| Medium | 4.9 | Medium4.9GCVE Database ## Summary The `/api/users/metadata` and `/api/users/metadata/:id` endpoints in `@budibase/server` return full global user profiles to any user with POWER role or above. For SSO-authenticated users (OIDC, Google), the response includes `oauth2.accessToken` and `oauth2.refreshToken` fields, leaking identity provider credentials to other users who should not have access to them. ## Details When a user authenticates via SSO (OIDC or Google), the OAuth2 tokens are stored in the global CouchDB user document at `packages/backend-core/src/auth/auth.ts:170-173`: ```typescript dbUser.oauth2 = { ...dbUser.oauth2, ...details, } await db.put(dbUser) ``` The user metadata endpoints are protected by `PermissionType.USER, PermissionLevel.READ` (`packages/server/src/api/routes/user.ts:11`), which maps to the POWER permission set (`packages/backend-core/src/security/permissions.ts:99`). **Path 1 — List all users** (`GET /api/users/metadata`): 1. `controller.fetchMetadata` → `sdk.users.fetchMetadata()` (`packages/server/src/sdk/users/utils.ts:78`) 2. → `getGlobalUsers()` → `getRawGlobalUsers()` (`packages/server/src/utilities/global.ts:101-122`) — strips only `password` and `forceResetPassword` 3. → `processUser()` (`packages/server/src/utilities/global.ts:15-76`) — strips only `password` and `roles` 4. The `oauth2` field containing `accessToken` and `refreshToken` is **never removed** **Path 2 — Single user** (`GET /api/users/metadata/:id`): 1. `controller.findMetadata` → `getFullUser()` (`packages/server/src/utilities/users.ts:6`) 2. → `getGlobalUser()` → `getRawGlobalUser()` (`packages/server/src/utilities/global.ts:90-92`) — raw CouchDB fetch, **no field stripping at all** 3. → `processUser()` — strips only `password` and `roles` 4. Same result: `oauth2` tokens are returned There is no output sanitization middleware on these routes that would strip sensitive fields before the response reaches the client. ## PoC **Prerequisites:** A Budibase instance with at least one SSO-authenticated user (OIDC or Google) and a separate user with POWER role in an app. **Step 1 — As the POWER user, list all users:** ```bash curl -s -X GET 'http://localhost:10000/api/users/metadata' \ -H 'Cookie: budibase:auth=<power-user-jwt>' \ -H 'x-budibase-app-id: app_<appid>' | jq '.[].oauth2' ``` **Expected output:** `null` for all users (tokens should not be exposed) **Actual output:** For SSO users, the response includes: ```json { "accessToken": "ya29.a0ARrdaM...", "refreshToken": "1//0eXxXxXxXx..." } ``` **Step 2 — Fetch a specific SSO user's profile:** ```bash curl -s -X GET 'http://localhost:10000/api/users/metadata/ro_ta_users_us_<sso-user-id>' \ -H 'Cookie: budibase:auth=<power-user-jwt>' \ -H 'x-budibase-app-id: app_<appid>' | jq '.oauth2' ``` This also returns the full OAuth2 tokens. ## Impact - A user with POWER role in any app can read **all SSO users' OAuth2 access tokens and refresh tokens** via the list endpoint, without needing to know individual user IDs. - Stolen access tokens can be used to access external identity provider resources (Google Workspace, Azure AD, Okta-protected services) as the victim user. - Refresh tokens allow indefinite token renewal, persisting access even after the original access token expires. - Additionally, `admin`, `builder`, `tenantId`, `ssoId`, and `userGroups` fields are leaked, revealing the full authorization topology of the instance. ## Recommended Fix Strip sensitive SSO fields in `processUser()` at `packages/server/src/utilities/global.ts:15`: ```typescript export async function processUser( user: ContextUser, opts: { appId?: string; groups?: UserGroup[] } = {} ) { if (!user || (!user.roles && !user.userGroups)) { return user } user = cloneDeep(user) delete user.password + delete (user as any).oauth2 + delete (user as any).provider + delete (user as any).providerType + delete (user as any).thirdPartyProfile + delete (user as any).profile + delete (user as any).ssoId + delete (user as any).forceResetPassword // ... rest of function ``` Additionally, `getRawGlobalUsers()` at line 101 should also strip `oauth2` alongside its existing `password`/`forceResetPassword` stripping for defense in depth. | GCVE Database | |||
| Malicious | – | MaliciousGCVE Database The npm package 'subapp-pkg-util' versions 99.0.0 and 99.0.1 contains malicious code that executes automatically upon installation. It collects detailed host information including OS details, user info, public IP, and geolocation data, then sends this data to a hardcoded external domain associated with malicious activity. The package is identified as a dependency-confusion proof-of-concept but acts as malware by compromising the host system. Removal of the package does not guarantee full remediation due to potential further compromise. | GCVE Database | |||
| High | 8.4 | EPSS 0.4% | CVE-2026-66140Exim4: Exim before 4.99.5 allows directory traversal to access files outside of the spool area, and consequently gain High8.4EPSS 0.4%GCVE DatabaseCVE-2026-66140 Exim versions before 4.99.5 contain a directory traversal vulnerability that allows attackers to access files outside the intended spool area by mishandling queue-name related arguments. This flaw can lead to privilege escalation. The vulnerability affects multiple Ubuntu LTS versions with Exim packages prior to specific patched versions. EPSS 0.4%Vulnerability | GCVE Database | ||
| High | 7.8 | EPSS 0.1% | CVE-2026-66141Exim4 · Exim before 4.99.5 allows .forward privilege escalation because force_command for a pipe High7.8EPSS 0.1%GCVE DatabaseCVE-2026-66141 Exim versions before 4.99.5 contain a vulnerability that allows privilege escalation via mishandling of force_command in a pipe transport for .forward files. This flaw can be exploited locally to gain elevated privileges. The issue affects multiple Ubuntu LTS versions with Exim packages prior to specific patched versions. EPSS 0.1%Vulnerability | GCVE Database |
Page 5 of 17