GCVE Workshop - 22 September 2026 (14:00-18:00), Luxembourg Before The Vulnopticon Conference - Registration

GHSA-QGVM-J2HM-6M38

Vulnerability from github – Published: 2026-08-04 19:37 – Updated: 2026-08-04 19:37
VLAI
Summary
Flowise: Unauthenticated OAuth2 token refresh endpoint returns access tokens — enables token theft for any connected service
Details

Summary

The OAuth2 token refresh endpoint (POST /api/v1/oauth2-credential/refresh/:credentialId) is in WHITELIST_URLS, meaning it requires no authentication. It decrypts the stored credential (containing clientId, clientSecret, refresh_token), sends a refresh request to the configured OAuth provider, and returns the new access_token directly in the response body.

Root Cause

// packages/server/src/routes/oauth2/index.ts:393-402
res.json({
    success: true,
    message: 'OAuth2 token refreshed successfully',
    credentialId: credential.id,
    tokenInfo: {
        ...tokenData,  // ← includes access_token!
        has_new_refresh_token: !!tokenData.refresh_token,
        expires_at: updatedCredentialData.expires_at
    }
})

Whitelist entry at packages/server/src/utils/constants.ts:40.

Attack Chain

  1. Attacker obtains a credential ID (via Finding 2 / public chatflow leak, or enumeration)
  2. Attacker calls POST /api/v1/oauth2-credential/refresh/:credentialId (no auth required)
  3. Server decrypts credential, sends refresh request to OAuth provider with user's client_secret
  4. Server returns the new access_token in the response to the attacker
  5. Attacker uses the token to access the victim's connected service (Google, Microsoft, etc.)

Docker Validation

POST /api/v1/oauth2-credential/refresh/fake-uuid returns {"message":"Credential not found"} (not 401 Unauthorized), proving the endpoint processes the request without authentication.

Impact

  • OAuth2 access token theft for any connected service
  • Full access to the victim's third-party accounts (Google, Microsoft, GitHub, etc.)
  • Client secret transmitted to OAuth provider during refresh
  • Can also be used for DoS by exhausting refresh token quota

Suggested Fix

Remove the refresh endpoint from WHITELIST_URLS and require authentication:

// Remove from WHITELIST_URLS in constants.ts
// Add authentication check in the route handler

Credits

  • Shinobi Security - https://github.com/shinobisecurity
Show details on source website

{
  "affected": [
    {
      "database_specific": {
        "last_known_affected_version_range": "\u003c= 3.1.2"
      },
      "package": {
        "ecosystem": "npm",
        "name": "flowise"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "0"
            },
            {
              "fixed": "3.1.3"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    }
  ],
  "aliases": [
    "CVE-2026-70478"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-200"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2026-08-04T19:37:36Z",
    "nvd_published_at": null,
    "severity": "CRITICAL"
  },
  "details": "### Summary\n\nThe OAuth2 token refresh endpoint (`POST /api/v1/oauth2-credential/refresh/:credentialId`) is in `WHITELIST_URLS`, meaning it requires **no authentication**. It decrypts the stored credential (containing `clientId`, `clientSecret`, `refresh_token`), sends a refresh request to the configured OAuth provider, and returns the new `access_token` directly in the response body.\n\n### Root Cause\n\n```typescript\n// packages/server/src/routes/oauth2/index.ts:393-402\nres.json({\n    success: true,\n    message: \u0027OAuth2 token refreshed successfully\u0027,\n    credentialId: credential.id,\n    tokenInfo: {\n        ...tokenData,  // \u2190 includes access_token!\n        has_new_refresh_token: !!tokenData.refresh_token,\n        expires_at: updatedCredentialData.expires_at\n    }\n})\n```\n\nWhitelist entry at `packages/server/src/utils/constants.ts:40`.\n\n### Attack Chain\n\n1. Attacker obtains a credential ID (via Finding 2 / public chatflow leak, or enumeration)\n2. Attacker calls `POST /api/v1/oauth2-credential/refresh/:credentialId` (no auth required)\n3. Server decrypts credential, sends refresh request to OAuth provider with user\u0027s `client_secret`\n4. Server returns the new `access_token` in the response to the attacker\n5. Attacker uses the token to access the victim\u0027s connected service (Google, Microsoft, etc.)\n\n### Docker Validation\n\n`POST /api/v1/oauth2-credential/refresh/fake-uuid` returns `{\"message\":\"Credential not found\"}` (not 401 Unauthorized), proving the endpoint processes the request without authentication.\n\n### Impact\n\n- OAuth2 access token theft for any connected service\n- Full access to the victim\u0027s third-party accounts (Google, Microsoft, GitHub, etc.)\n- Client secret transmitted to OAuth provider during refresh\n- Can also be used for DoS by exhausting refresh token quota\n\n### Suggested Fix\n\nRemove the refresh endpoint from `WHITELIST_URLS` and require authentication:\n\n```typescript\n// Remove from WHITELIST_URLS in constants.ts\n// Add authentication check in the route handler\n```\n\n---\n\n## Credits\n\n- Shinobi Security - https://github.com/shinobisecurity",
  "id": "GHSA-qgvm-j2hm-6m38",
  "modified": "2026-08-04T19:37:36Z",
  "published": "2026-08-04T19:37:36Z",
  "references": [
    {
      "type": "WEB",
      "url": "https://github.com/FlowiseAI/Flowise/security/advisories/GHSA-qgvm-j2hm-6m38"
    },
    {
      "type": "PACKAGE",
      "url": "https://github.com/FlowiseAI/Flowise"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:H/VI:L/VA:N/SC:H/SI:L/SA:N",
      "type": "CVSS_V4"
    }
  ],
  "summary": "Flowise: Unauthenticated OAuth2 token refresh endpoint returns access tokens \u2014 enables token theft for any connected service"
}



Log in or create an account to share your comment.




Tags
Taxonomy of the tags.


Loading…

Loading…

Loading…

Forecast uses a logistic model when the trend is rising, or an exponential decay model when the trend is falling. Fitted via linearized least squares.

Sightings

Author Source Type Date Other

Nomenclature

  • Seen: The vulnerability was mentioned, discussed, or observed by the user.
  • Confirmed: The vulnerability has been validated from an analyst's perspective.
  • Published Proof of Concept: A public proof of concept is available for this vulnerability.
  • Exploited: The vulnerability was observed as exploited by the user who reported the sighting.
  • Patched: The vulnerability was observed as successfully patched by the user who reported the sighting.
  • Not exploited: The vulnerability was not observed as exploited by the user who reported the sighting.
  • Not confirmed: The user expressed doubt about the validity of the vulnerability.
  • Not patched: The vulnerability was not observed as successfully patched by the user who reported the sighting.

Loading…

Detection rules are retrieved from Rulezet.

Loading…

Loading…

Related by attack behaviour

Vulnerabilities whose description is nearest to this one in the vector space of the CIRCL/vulnerability-attack-technique-biencoder model. This is a similarity search over the bi-encoder space (plain cosine), not a classification, and it has no measured accuracy.


Loading…