@apideck/quickbooks-review-check 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/README.md +239 -24
  2. package/package.json +1 -1
package/README.md CHANGED
@@ -1,67 +1,276 @@
1
- # quickbooks-review-check
1
+ # Apideck QuickBooks Review Check
2
2
 
3
- **Free, open-source self-check for the Intuit QuickBooks Online app security review.** Run it before you submit, and on every deploy after you're listed, so the annual re-review doesn't catch you out.
3
+ [![npm](https://img.shields.io/npm/v/@apideck/quickbooks-review-check)](https://www.npmjs.com/package/@apideck/quickbooks-review-check)
4
+ [![License: MIT](https://img.shields.io/badge/license-MIT-blue)](LICENSE)
4
5
 
5
- It does two kinds of checks, both free:
6
+ **Free, open-source self-check for the Intuit QuickBooks Online app security review.** Run it before you submit, and on every deploy after you're listed, so Intuit's yearly re-review doesn't catch you out.
6
7
 
7
- | | What it checks | How |
8
- |---|---|---|
9
- | **Runtime** | HTTPS enforcement, TLS 1.0/1.1/1.2/1.3, certificate, HSTS, `Cache-Control: no-store` (not `private`) on sensitive pages, TRACE/TRACK disabled, `Secure` + `HttpOnly` session cookies, the **302 rule** on your OAuth callback, open redirects, version-banner disclosure, browser security headers | Probes your deployed app from outside |
10
- | **Source** | Refresh token **and realmId** encrypted at rest (AES/3DES), AES key not inline, tokens or `authResponse` logged, tokens sent to the browser / `localStorage`, hardcoded `state: 'testState'` (CSRF in Intuit's sample code), missing state validation, CSRF middleware, TLS verification disabled, weak ciphers (ECB, `createCipher`), SQL/QBO-query string interpolation, XSS sinks, XXE, QuickBooks data flowing into LLM/analytics/APM SDKs | Static scan of your repo (JS/TS, Python, Ruby, PHP, Java, C#, Go). No code leaves your machine. |
8
+ It applies to apps for **QuickBooks Online and Intuit Enterprise Suite**: Intuit's IES developer docs say IES apps follow the identical publishing steps and three-part review.
11
9
 
12
- Every result maps to one of Intuit's review categories. Each report ends with a **manual attestation checklist** for the items no scanner can prove: patching, access control, DAST, and the data-usage rules.
10
+ Try it in the browser at **[apideck.com/tools/quickbooks-review](https://www.apideck.com/tools/quickbooks-review)**, run it locally with `npx`, or add it to CI as a GitHub Action.
13
11
 
14
12
  > **Disclaimer.** This is a self-assessment aid, not a certification, penetration test, security audit or legal/compliance advice. Passing these checks does not mean an app meets Intuit's requirements or will be approved. Always confirm requirements against Intuit's official developer documentation. Only run runtime checks against apps you own or are authorized to test. Provided "as is" under the MIT License, without warranty.
15
13
  >
16
14
  > Not affiliated with, endorsed by or sponsored by Intuit Inc. Intuit and QuickBooks are trademarks of Intuit Inc., used only to describe what the tool checks against.
17
15
 
16
+ ## Contents
17
+
18
+ - [What it checks](#what-it-checks)
19
+ - [Quick start](#quick-start)
20
+ - [GitHub Action guide](#github-action-guide)
21
+ - [Reading the results](#reading-the-results)
22
+ - [CLI reference](#cli-reference)
23
+ - [Troubleshooting](#troubleshooting)
24
+ - [Fixing common findings](#fixing-common-findings)
25
+ - [Using Apideck?](#using-apideck)
26
+ - [Sample apps](#sample-apps)
27
+ - [Development](#development)
28
+
29
+ ## What it checks
30
+
31
+ | | What it checks | How |
32
+ |---|---|---|
33
+ | **Runtime** | HTTPS enforcement, TLS 1.0/1.1/1.2/1.3, certificate, HSTS, `Cache-Control: no-store` (not `private`) on sensitive pages, TRACE/TRACK disabled, `Secure` + `HttpOnly` session cookies, the **302 rule** on your OAuth callback, open redirects, version-banner disclosure, browser security headers | Ordinary HTTP requests and TLS handshakes against your deployed app |
34
+ | **Source** | Refresh token **and realmId** encrypted at rest (AES/3DES), encryption key not inline, tokens or `authResponse` logged, tokens sent to the browser or `localStorage`, a hardcoded `state: 'testState'` (CSRF, from Intuit's sample code), missing state validation, CSRF middleware, TLS verification disabled, weak ciphers (ECB, `createCipher`), SQL and QuickBooks-query string interpolation, XSS sinks, XXE, QuickBooks data near LLM/analytics/APM SDKs | Pattern-based scan of your repo (JS/TS, Python, Ruby, PHP, Java, C#, Go). Nothing is uploaded. |
35
+
36
+ Every result maps to one of Intuit's review areas. Each report ends with a **sign-off checklist** for what no scanner can prove: patching, access control, a penetration test or DAST scan, and the QuickBooks data-usage rules.
37
+
18
38
  ## Quick start
19
39
 
40
+ **In the browser:** [apideck.com/tools/quickbooks-review](https://www.apideck.com/tools/quickbooks-review). Probe a deployed app, or pick a folder to scan in the browser, and download an auditor-style PDF report.
41
+
42
+ **From your terminal** (Node 20 or later, nothing to install):
43
+
20
44
  ```bash
21
45
  npx @apideck/quickbooks-review-check \
22
46
  --url https://app.example.com \
23
47
  --callback /oauth/quickbooks/callback \
24
- --path /dashboard --path /settings/quickbooks \
48
+ --path /dashboard \
25
49
  --header "Cookie: session=…" \
26
50
  --source .
27
51
  ```
28
52
 
29
- - `--callback` is the Redirect URI you registered with Intuit. The tool calls it with a fake `code`, `state` and `realmId`, and checks that it answers with a `302`, not HTML.
30
- - `--path` names sensitive pages that must send `no-store`. Pass a session cookie with `--header` so they're checked while signed in, not as a redirect to the login page.
31
- - `--markdown report.md` and `--json report.json` write reports. `--fail-on warn|fail|never` controls the exit code.
32
-
33
- ## GitHub Action
53
+ **In CI:** add `.github/workflows/quickbooks-review.yml`:
34
54
 
35
55
  ```yaml
36
56
  name: QuickBooks review check
37
57
  on:
38
- deployment_status:
39
- schedule: [{ cron: '0 6 * * 1' }] # weekly, catches drift before Intuit's annual re-review
40
58
  pull_request:
59
+ schedule:
60
+ - cron: '0 6 * * 1' # every Monday
61
+
62
+ jobs:
63
+ check:
64
+ runs-on: ubuntu-latest
65
+ steps:
66
+ - uses: actions/checkout@v4
67
+ - uses: apideck-libraries/quickbooks-review-check@v0
68
+ with:
69
+ url: https://app.example.com
70
+ callback: /oauth/quickbooks/callback
71
+ ```
72
+
73
+ The report appears in the workflow run's job summary.
74
+
75
+ ## GitHub Action guide
76
+
77
+ ### Inputs
78
+
79
+ | Input | Default | Description |
80
+ |---|---|---|
81
+ | `url` | | Base URL of the deployed app. Runs the runtime checks. Leave empty to only scan source. |
82
+ | `callback` | | Your OAuth redirect URI path, as registered with Intuit (e.g. `/oauth/quickbooks/callback`). Checks the 302 rule, caching and cookies on it. |
83
+ | `paths` | | Sensitive pages that must not be cached, one per line (e.g. `/dashboard`). |
84
+ | `headers` | | Extra request headers, one per line. Use it to send a session cookie so signed-in pages are checked. Always pass values from secrets. |
85
+ | `source` | `.` | Directory to scan. Set to `''` to skip the source scan. |
86
+ | `fail-on` | `fail` | When the step fails: `fail` (any failed check), `warn` (also on warnings) or `never`. |
87
+
88
+ ### Outputs
89
+
90
+ | Output | Description |
91
+ |---|---|
92
+ | `report` | Path to the Markdown report |
93
+ | `report-json` | Path to the JSON report |
94
+ | `failed` | Number of failed checks |
95
+ | `warnings` | Number of warnings |
96
+ | `passed` | Number of passed checks |
97
+
98
+ The outputs are set even when the step fails, so later steps with `if: always()` can use them.
99
+
100
+ ### Recipe: check every deployment
101
+
102
+ Run after each successful deploy (Vercel, Netlify, Render and others create GitHub deployments) against the URL that was just deployed:
103
+
104
+ ```yaml
105
+ on: deployment_status
106
+
107
+ jobs:
108
+ check:
109
+ if: github.event.deployment_status.state == 'success'
110
+ runs-on: ubuntu-latest
111
+ steps:
112
+ - uses: actions/checkout@v4
113
+ with:
114
+ ref: ${{ github.event.deployment.sha }}
115
+ - uses: apideck-libraries/quickbooks-review-check@v0
116
+ with:
117
+ url: ${{ github.event.deployment_status.environment_url }}
118
+ callback: /oauth/quickbooks/callback
119
+ ```
120
+
121
+ If preview deployments sit behind a login (for example Vercel Deployment Protection), point `url` at production instead, or pass the provider's bypass header through `headers`.
122
+
123
+ ### Recipe: weekly drift check
124
+
125
+ Listed apps are reviewed again by Intuit. A weekly run catches a changed header or proxy setting long before that:
126
+
127
+ ```yaml
128
+ on:
129
+ schedule:
130
+ - cron: '0 6 * * 1'
131
+ workflow_dispatch:
132
+ ```
133
+
134
+ ### Recipe: source-only check on pull requests
135
+
136
+ No deployed URL needed. Catches a new `console.log(token)` or a hardcoded key before merge:
137
+
138
+ ```yaml
139
+ on: pull_request
41
140
 
42
141
  jobs:
43
142
  check:
44
143
  runs-on: ubuntu-latest
45
144
  steps:
46
145
  - uses: actions/checkout@v4
146
+ - uses: apideck-libraries/quickbooks-review-check@v0
147
+ with:
148
+ source: .
149
+ ```
150
+
151
+ ### Recipe: check signed-in pages
152
+
153
+ Without a session, sensitive pages usually redirect to your login page, and the cache check can't see them. Create a dedicated test account, copy its session cookie into a repository secret (Settings → Secrets and variables → Actions → `QBRC_SESSION_COOKIE`), then:
154
+
155
+ ```yaml
47
156
  - uses: apideck-libraries/quickbooks-review-check@v0
48
157
  with:
49
158
  url: https://app.example.com
50
159
  callback: /oauth/quickbooks/callback
51
160
  paths: |
52
161
  /dashboard
53
- /settings/quickbooks
162
+ /settings/integrations
54
163
  headers: |
55
164
  Cookie: ${{ secrets.QBRC_SESSION_COOKIE }}
56
- source: .
57
- fail-on: fail
58
165
  ```
59
166
 
60
- The Markdown report is written to the job summary. To scan source only (e.g. on pull requests), omit `url`.
167
+ Use a test account with no real customer data, and rotate the cookie when it expires.
168
+
169
+ ### Recipe: keep the report as an artifact
170
+
171
+ ```yaml
172
+ - id: qbo
173
+ uses: apideck-libraries/quickbooks-review-check@v0
174
+ with:
175
+ url: https://app.example.com
176
+ - if: always()
177
+ uses: actions/upload-artifact@v4
178
+ with:
179
+ name: quickbooks-review
180
+ path: |
181
+ ${{ steps.qbo.outputs.report }}
182
+ ${{ steps.qbo.outputs.report-json }}
183
+ ```
184
+
185
+ ### Recipe: alert on failures without blocking
186
+
187
+ ```yaml
188
+ - id: qbo
189
+ uses: apideck-libraries/quickbooks-review-check@v0
190
+ with:
191
+ url: https://app.example.com
192
+ fail-on: never
193
+ - if: steps.qbo.outputs.failed != '0'
194
+ run: |
195
+ curl -X POST -H 'Content-type: application/json' \
196
+ --data "{\"text\":\"QuickBooks review check: ${{ steps.qbo.outputs.failed }} failed, ${{ steps.qbo.outputs.warnings }} warnings\"}" \
197
+ "${{ secrets.SLACK_WEBHOOK_URL }}"
198
+ ```
199
+
200
+ ## Reading the results
201
+
202
+ Each check has one of five statuses:
203
+
204
+ | Status | Meaning |
205
+ |---|---|
206
+ | **Fail** | The control is missing or wrong. Expect Intuit to flag it. |
207
+ | **Warn** | Partly in place, or worth a look (source patterns can be false positives). |
208
+ | **Pass** | The control is in place. |
209
+ | **Info** | Context, such as the HTTP methods your server advertises. |
210
+ | **Skip** | Not checked, for example no cookies were seen or no callback was given. |
211
+
212
+ Results are grouped by Intuit's review areas: server and transport, attack vulnerabilities, cookies and sessions, OAuth token management, the token-endpoint redirect rule, and QuickBooks data usage. Each finding includes the evidence (the response header or `file:line`) and a fix.
213
+
214
+ The website version adds a PDF report with severities (High, Medium, Low), evidence, remediation and a sign-off page, which is useful to keep with your submission. Intuit requires critical, high and medium issues found in its review to be fixed before an app is published.
215
+
216
+ **Exit codes:** `0` all good (for the chosen `--fail-on`), `1` failures found, `2` usage error.
217
+
218
+ ## CLI reference
219
+
220
+ ```text
221
+ npx @apideck/quickbooks-review-check [options]
222
+
223
+ Runtime checks (probe your deployed app):
224
+ --url <url> Base URL of your deployed app
225
+ --callback <path> OAuth redirect URI path (checks the 302 rule, cache headers, cookies)
226
+ --path <path> Sensitive page to check for no-store caching (repeatable)
227
+ --header "K: V" Extra request header, e.g. a session cookie (repeatable)
228
+ --timeout <ms> Per-request timeout (default 10000)
229
+ --http-port <port> Port for the plain-HTTP redirect check (default 80; for local testing)
230
+
231
+ Source checks (static scan of your code):
232
+ --source <dir> Scan a repository for token-handling issues
233
+ --include-tests Also scan test/example files
234
+
235
+ Output:
236
+ --markdown <file> Write a Markdown report ("-" for stdout)
237
+ --json <file> Write a JSON report ("-" for stdout)
238
+ --fail-on <level> Exit 1 on: fail (default) | warn | never
239
+ -q, --quiet Don't print the console report
240
+ ```
241
+
242
+ Examples:
61
243
 
62
- ## Encrypting the refresh token (Node)
244
+ ```bash
245
+ # Source only, Markdown report to a file
246
+ npx @apideck/quickbooks-review-check --source . --markdown quickbooks-review.md
247
+
248
+ # Runtime only, JSON to stdout for scripting
249
+ npx @apideck/quickbooks-review-check --url https://app.example.com --json - --quiet | jq '.summary'
63
250
 
64
- Intuit requires the refresh token and realmId to be encrypted with AES (preferred) or 3DES, with the key kept out of your code:
251
+ # Fail the build on warnings too
252
+ npx @apideck/quickbooks-review-check --source . --fail-on warn
253
+ ```
254
+
255
+ ## Troubleshooting
256
+
257
+ **"Callback /oauth/callback returned 404".** The `callback` path must match the Redirect URI registered in the Intuit developer portal, exactly.
258
+
259
+ **"Cache-Control not checked on /dashboard".** The page redirected, usually to your login. Pass a session cookie with `headers` / `--header`.
260
+
261
+ **The callback answers 4xx with JSON.** That passes. It means your app rejected the fake test code without rendering a page. A real authorization should still end in a 302, which you can confirm with a real connect flow.
262
+
263
+ **"TLS 1.0 not testable".** Your runner's OpenSSL can't offer TLS 1.0. The other TLS results are still valid.
264
+
265
+ **TRACE shows as refused.** A firewall or CDN blocking TRACE counts as disabled, which is what Intuit wants.
266
+
267
+ **The source scan flags something that's fine.** It matches patterns, so for example an `innerHTML` that only renders static text shows as a warning. Treat warnings as prompts to look.
268
+
269
+ **Internal or private URLs.** The hosted scanner on apideck.com only checks public hosts on ports 80/443. Run the CLI or the Action inside your network for anything else.
270
+
271
+ ## Fixing common findings
272
+
273
+ The **[requirements guide](https://www.apideck.com/tools/quickbooks-review/checklist)** explains every check, with a command to verify it and fixes for Express, Next.js, nginx, Django and Rails. The fix Intuit reviewers ask about most is encrypting the refresh token and realmId with AES (preferred) or 3DES, with the key kept out of your code. In Node:
65
274
 
66
275
  ```js
67
276
  import crypto from 'node:crypto';
@@ -84,7 +293,7 @@ export function decrypt(blob) {
84
293
 
85
294
  ## Using Apideck?
86
295
 
87
- If your app connects to QuickBooks through [Apideck Vault](https://www.apideck.com), Apideck stores and encrypts the Intuit OAuth tokens and realmId. Your app never holds them, and the scanner recognizes this setup. Ask Apideck for its security documentation if your reviewer wants details on token storage. You still own the runtime checks (HTTPS, cookies, cache headers) and the data-usage rules for your app, and this tool covers those.
296
+ If your app connects to QuickBooks through [Apideck](https://www.apideck.com/accounting-api), you still register your own Intuit app and go through Intuit's review, but the OAuth redirect URI, token exchange, token storage and refresh run on Apideck Vault. Your app never holds the Intuit tokens, and the scanner recognizes this setup. You still own the runtime checks (HTTPS, cookies, cache headers) and the data-usage rules for your app, and this tool covers those.
88
297
 
89
298
  ## Sample apps
90
299
 
@@ -101,11 +310,17 @@ node bin/quickbooks-review-check.js --url https://localhost:8443 --http-port 808
101
310
 
102
311
  `node examples/record.js <dir>` re-records both apps' scan results and source files for the website's "Try a sample" buttons.
103
312
 
313
+ ## Releasing
314
+
315
+ Bump `version` in `package.json`, merge, then push a matching tag (`git tag v0.2.0 && git push origin v0.2.0`). The Release workflow runs the tests, publishes to npm with provenance via trusted publishing, and moves the major tag (`v0`) the GitHub Action uses.
316
+
104
317
  ## Development
105
318
 
106
319
  ```bash
107
- npm test # node:test, zero dependencies
320
+ npm test # node:test, zero dependencies; includes the end-to-end test against both sample apps
108
321
  node bin/quickbooks-review-check.js --source test/fixtures/insecure --fail-on never
109
322
  ```
110
323
 
324
+ Issues and pull requests for new checks are welcome.
325
+
111
326
  MIT © Apideck
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@apideck/quickbooks-review-check",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "description": "Free self-check for the Intuit QuickBooks Online app security review: runtime probes + source scan, as a CLI and GitHub Action.",
5
5
  "type": "module",
6
6
  "bin": {