PT-2025-45801 · Npm · @Actual-App/Sync-Server

Published

2025-10-20

·

Updated

2025-10-20

CVSS v3.1

4.2

Medium

VectorAV:L/AC:L/PR:H/UI:R/S:U/C:H/I:N/A:N

Summary

The GoCardless components in Actualbudget in are logging responses to STDOUT in a parsed format using console.logand console.debug (Which in this version of node is an alias for console.log). This is exposing sensitive information in log files including, but not limited to:
  • Gocardless bearer tokens.
  • Account IBAN and Bank Account numbers.
  • PII of the account holder.
  • Transaction details (Payee bank information, Recipient account numbers, Transaction IDs)...

Details

This in turn logs the following information to Docker (all values removed here. These fields are possibly dependent on what is returned by each institution so may differ):
json
{
 "account": {
  "resourceId": "",
  "iban": "",
  "bban": "",
  "currency": "",
  "name": "<full legal name in the bank>",
  "product": "",
  "status": "",
  "bic": "",
  "usage": "",
  "id": "",
  "created": "",
  "last accessed": "",
  "institution id": "",
  "owner name": "",
  "institution": {
   "id": "",
   "name": "",
   "bic": "",
   "transaction total days": "",
   "countries": [
    ""
   ],
   "logo": "",
   "max access valid for days": "",
   "supported features": [
    "",
    "",
    ""
   ],
   "identification codes": []
  }
 }
}
This is the first of the 10 transactions:
json
{
 "top10Transactions": [{
  "transactionId": "",
  "entryReference": "",
  "bookingDate": "",
  "valueDate": "",
  "transactionAmount": {
   "amount": "",
   "currency": ""
  },
  "creditorName": "",
  "creditorAccount": {
   "bban": ""
  },
  "debtorName": "",
  "debtorAccount": {
   "bban": ""
  },
  "remittanceInformationUnstructured": "",
  "remittanceInformationStructuredArray": [
   {"reference": "", "referenceType": ""}
  ],
  "additionalInformation": "",
  "proprietaryBankTransactionCode": "",
  "debtorAgent": "",
  "internalTransactionId": "",
  "payeeName": "",
  "date": ""
 }]
}
Additionally, in the error handling for GoCardless, there is a catch all for unclassified errors that prints the entire stack trace to the console.
Our bank was offline today for maintenance which threw a 503 error from Gocardless. The entire response payload was dumped to console, which includes the Bearer tokens for accessing GoCardless:
java
Something went wrong ServiceError: Institution service unavailable
  at handleGoCardlessError (file:///app/src/app-gocardless/services/gocardless-service.js:59:13)
  at Object.getTransactions (file:///app/src/app-gocardless/services/gocardless-service.js:530:7)
  at process.processTicksAndRejections (node:internal/process/task queues:95:5)
  at async Object.getNormalizedTransactions (file:///app/src/app-gocardless/services/gocardless-service.js:267:26)
  at async file:///app/src/app-gocardless/app-gocardless.js:186:13 {
 details: h [AxiosError]: Request failed with status code 503
   at te (file:///app/node modules/nordigen-node/dist/index.esm.js:13:914)
   at IncomingMessage.<anonymous> (file:///app/node modules/nordigen-node/dist/index.esm.js:17:16315)
   at IncomingMessage.emit (node:events:529:35)
   at endReadableNT (node:internal/streams/readable:1400:12)
   at process.processTicksAndRejections (node:internal/process/task queues:82:21) {
  code: 'ERR BAD RESPONSE',
  config: {
   transitional: {
    silentJSONParsing: true,
    forcedJSONParsing: true,
    clarifyTimeoutError: false
   },
   adapter: [ 'xhr', 'http' ],
   transformRequest: [ [Function (anonymous)] ],
   transformResponse: [ [Function (anonymous)] ],
   timeout: 0,
   xsrfCookieName: 'XSRF-TOKEN',
   xsrfHeaderName: 'X-XSRF-TOKEN',
   maxContentLength: -1,
   maxBodyLength: -1,
   env: {
    FormData: [Function: ] {
     LINE BREAK: 'r
',
     DEFAULT CONTENT TYPE: 'application/octet-stream'
    },
    Blob: [class Blob]
   },
   validateStatus: [Function: validateStatus],
   headers: T [AxiosHeaders] {
    Accept: 'application/json',
    'Content-Type': 'application/json',
    'User-Agent': 'Nordigen-Node-v2',
    'Authorization': 'Bearer eyJ0eXAi... (the full token is in the response)',
    'Accept-Encoding': 'gzip, compress, deflate, br'
   },
   method: 'get',
   url: URL {
    href: 'https://bankaccountdata.gocardless.com/api/v2/accounts/<Account id Was Here>?date from=2024-12-22',
    origin: 'https://bankaccountdata.gocardless.com',
    protocol: 'https:',
    username: '',
    password: '',
    host: 'bankaccountdata.gocardless.com',
    hostname: 'bankaccountdata.gocardless.com',
    port: '',
    pathname: '/api/v2/accounts/<Account id Was Here>/transactions',
    search: '?date from=2024-12-22',
    searchParams: URLSearchParams { 'date from' => '2024-12-22' },
    hash: ''
   },
   data: undefined
  },
And quite a few pages more.

PoC

Impact

Information disclosure. The services are available both on-premises and in environments that are not under the control of the end user, such as third-party providers who offer this application as a managed solution.

Fix

Generation of Error Message Containing Sensitive Information

Found an issue in the description? Have something to add? Feel free to write us 👾

Weakness Enumeration

Related Identifiers

GHSA-XVP7-8VM8-XFXX

Affected Products

@Actual-App/Sync-Server