Skip to content

Secure resource-backed E2E endpoints#87

Open
larohra wants to merge 30 commits into
Azure:mainfrom
larohra:swarm/23b2164a/integration
Open

Secure resource-backed E2E endpoints#87
larohra wants to merge 30 commits into
Azure:mainfrom
larohra:swarm/23b2164a/integration

Conversation

@larohra
Copy link
Copy Markdown

@larohra larohra commented May 12, 2026

Context / assessment

  • The reported findings are not generic scanner noise: each flagged route is an HTTP trigger directly wired to Table, Cosmos DB, SQL, Storage Queue, or Service Bus bindings. In any Azure-hosted or shared environment, anonymous callers can read or write real backing resources.
  • The repo’s current operating model lowers immediate exploitability: README.md, src/global.test.ts, and the pipeline show a localhost-only E2E harness (func start on 127.0.0.1 plus storage/Cosmos/Service Bus/SQL emulators). There is no in-repo deployment flow to a public Azure Function App.
  • The fixes are still necessary. These are true-positive patterns on sensitive bindings, and equivalent v4/oldConfig endpoints use the same anonymous design even though the SFI report only enumerated v3 files.
  • This is primarily an auth/IDOR problem, not SQL injection: the SQL input binding already uses a parameterized query. Validation is defense in depth; requiring auth and reducing surface area are the primary controls.

Historical context

  • Git history shows these endpoints were introduced to expand binding coverage and keep the E2E harness simple (cosmos db test, Add extra output tests for storage/serviceBus (#12), Add table input/output test (#16), Emulate Storage and CosmosDB E2E Tests (#62)).
  • Anonymous auth appears to have been an intentional convenience choice for fetch-based tests, not a production threat model. There is no evidence of later hardening or auth-focused regression tests.

Planned change shape

  1. Harden only the resource-backed HTTP routes in v3, v4, and oldConfig equivalents; leave non-sensitive anonymous routes (hello world, headers, query, cookies, etc.) unchanged.
  2. Change auth from anonymous to function and narrow HTTP verbs to least privilege: GET for read endpoints, POST for write endpoints.
  3. Add minimal guard clauses instead of overly strict schemas:
    • reject missing or malformed rowKey/id/request bodies with 400,
    • return 404 when a lookup resolves to no resource,
    • validate required payload fields before queue/table/cosmos/sql writes,
    • preserve current happy-path payloads, status codes, and log messages.
  4. Add static regression coverage that inspects sensitive route definitions so auth cannot drift back to anonymous or broader methods, because local Core Tools does not enforce function-key auth.
  5. Document the hosted-call contract (code query string or x-functions-key) and, if practical, let test helpers append an env-supplied key for future hosted runs without changing local behavior.

Regressions / breaking change

  • Local CI should not regress from the auth-level change alone because Azure Functions Core Tools disables HTTP auth enforcement when running locally. The main behavioral regression risk is the new request validation, so negative-path tests are needed.
  • Any deployed consumer calling these endpoints anonymously will see a deliberate breaking change and must send a function key. Tightening verbs can also break callers that currently use POST for reads or GET for writes.
  • Because this repo is an E2E harness rather than a customer-facing service, production impact is limited, but the contract change should still be documented clearly.

Test state

  • Existing happy-path E2E coverage is good: src/storage.test.ts, src/serviceBus.test.ts, src/cosmosDB.test.ts, and src/sql.test.ts exercise the flagged flows across v3/v4, and combined oldConfig runs cover the legacy Cosmos paths.
  • Coverage is weak for security regression: there are no auth-focused checks, no malformed-input coverage for these endpoints, and no static assertions on auth level or HTTP methods.
  • We cannot fully prove Azure-hosted auth enforcement inside the current emulator-only suite, so the plan adds static config guards plus E2E validation tests for 400/404 behavior.

swarm-bot and others added 12 commits May 12, 2026 13:20
…arison

- Add `hasValidOutputEnvelope` to v4's httpValidation.ts, mirroring the v3
  validator: requires output to be a non-empty string or non-empty array of
  non-empty strings (not just existence-checked)
- Update httpTriggerServiceBusOutput and httpTriggerStorageQueueOutput in v4
  to use `hasValidOutputEnvelope` instead of `hasDefinedField`, so that empty
  strings, null, or empty arrays are now rejected with 400 (same behaviour as
  v3)
- Replace order-sensitive index comparison in `assertMethods` inside
  check-sensitive-http-routes.js with a Set-based comparison so multi-method
  routes with different orderings won't produce false failures

Agent-Logs-Url: https://github.com/larohra/azure-functions-nodejs-e2e-tests/sessions/fcdb4628-26a8-41f1-a6dd-e440b33d7c9f

Co-authored-by: larohra <41490930+larohra@users.noreply.github.com>
…ST_KEY

- Add `npm run testSecurityRegression` step to azure-pipelines/templates/build.yml
  so the static auth/method check gates every PR and build run
- Document the FUNCTIONS_TEST_KEY env var in README.md, explaining that
  getFuncUrl() automatically appends ?code=<key> when the var is set, making
  the same test suite work for both local Core Tools and hosted Azure Function App runs

Agent-Logs-Url: https://github.com/larohra/azure-functions-nodejs-e2e-tests/sessions/504baf4a-8c69-4c78-b681-5da4970b0135

Co-authored-by: larohra <41490930+larohra@users.noreply.github.com>
@larohra larohra requested a review from a team as a code owner May 12, 2026 21:54
Copilot AI and others added 17 commits May 12, 2026 22:13
ESLint no-useless-escape errors in four v4 files — double quotes inside
backtick template literals don't need escaping. Removed the backslashes
from the error message strings in:
- app/v4/src/functions/httpTriggerCosmosDBInput.ts
- app/v4/src/functions/httpTriggerSqlInput.ts
- app/v4/src/functions/httpTriggerTableInput.ts
- app/v4/src/utils/httpValidation.ts

Agent-Logs-Url: https://github.com/larohra/azure-functions-nodejs-e2e-tests/sessions/8e25b030-0a25-45ee-a920-d163354a019c

Co-authored-by: larohra <41490930+larohra@users.noreply.github.com>
…capes

v4-oldConfig/src/utils/httpValidation.ts was missing the
hasValidOutputEnvelope export that v4's httpTriggerServiceBusOutput and
httpTriggerStorageQueueOutput import after the previous hardening commit.
When createCombinedApps overlays v4-oldConfig on top of v4, its
httpValidation.ts overwrote the v4 version that had the export, causing
a TypeScript compile error in the combined v4-oldConfig build.

Fix:
- Add hasValidOutputEnvelope to v4-oldConfig/src/utils/httpValidation.ts
  (identical implementation to v4)
- Remove unnecessary \" escape sequences in v4-oldConfig template literals
  and string literals (httpValidation.ts lines 35/44,
  httpTriggerCosmosDBInput.ts line 26,
  httpTriggerCosmosDBOutput.ts line 25)

Validated locally:
- root e2e tests: build, lint, testSecurityRegression — all pass
- app/v3: build, lint — pass
- app/v4: build, lint — pass
- app/combined/v3-oldConfig: build — pass
- app/combined/v4-oldConfig: build — pass (no more TS2305 error)

Agent-Logs-Url: https://github.com/larohra/azure-functions-nodejs-e2e-tests/sessions/befa8dc5-88c2-4c15-8d25-bb30997859ed

Co-authored-by: larohra <41490930+larohra@users.noreply.github.com>
In v3, binding extensions resolve {Query.id} before function code runs.
When the query parameter is missing, the SQL/CosmosDB binding extensions
fail with HTTP 500 before our validation code can return 400. The v4
runtime handles these cases more gracefully (bindings return null
instead of throwing).

Skip the 'reject invalid requests' tests for v3 model. The endpoint
hardening (auth level, HTTP methods, validation code) remains in place
and is verified by the static check-sensitive-http-routes.js script.

Validated locally:
- root: build, lint, testSecurityRegression — all pass
- app/v3: build, lint — pass
- app/v4: build, lint — pass
- app/combined/v3-oldConfig: build — pass
- app/combined/v4-oldConfig: build — pass

Agent-Logs-Url: https://github.com/larohra/azure-functions-nodejs-e2e-tests/sessions/d8c1211c-53cc-41c0-acc7-f410ab322be6

Co-authored-by: larohra <41490930+larohra@users.noreply.github.com>
Restore binding-compatible Cosmos/SQL E2Es
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants