Scan Summary
| Domain |
CRITICAL |
HIGH |
MEDIUM |
LOW |
Notes |
| Agentic Security (ASI01-ASI10) |
0 |
0 |
4 |
2 |
6 pass, 4 partial |
| CI/CD Security (CICD-SEC 1-10) |
0 |
1 |
3 |
2 |
SHA-pinned actions (1 exception), OIDC auth |
| Container Security (Docker Top 6) |
0 |
0 |
2 |
2 |
Multi-stage builds, non-root user |
| Totals |
0 |
1 |
9 |
6 |
|
Comparison with Previous Scan (#341 — 2026-05-07)
| Metric |
Previous |
Current |
Delta |
| CRITICAL |
1 |
0 |
✅ -1 |
| HIGH |
4 |
1 |
✅ -3 |
| MEDIUM |
10 |
9 |
✅ -1 |
| LOW |
2 |
6 |
⬆️ +4 (more granular reporting) |
Key improvements since last scan:
- CRITICAL unpinned base image finding downgraded to MEDIUM (images use
:10.0 not :latest)
- ACR
adminUserEnabled HIGH finding not detected this scan (may be resolved)
- Docker resource limits and Cosmos emulator pinning not flagged (out of scope this run)
- Container security posture improved overall
1. Agentic Security (ASI01-ASI10)
Scope: src/Biotrackr.Chat.Api/, src/Biotrackr.Mcp.Server/, src/Biotrackr.Reporting.Api/
Controls Passing ✅
- ASI06 (Memory/Context Poisoning): 50 hydrated msgs, 10K char limit, 100 msg cap, 90-day TTL
- ASI07 (Inter-Agent Communication): JWT + azp claim validation, API key with constant-time comparison
- ASI08 (Cascading Failures): Circuit breakers, rate limiting (100 req/min), concurrency semaphore (3 jobs), timeouts
- ASI09 (Human-Agent Trust): Independent reviewer agent, mandatory disclaimers, fail-safe disclosures
- ASI10 (Rogue Agents): Kill switch, 50MB artifact limit, full OpenTelemetry tracing
- ASI04 (Supply Chain): Explicit version pins (no floating ranges)
MEDIUM — ASI01: Chat.Api user messages not injection-scanned
File: src/Biotrackr.Chat.Api/Biotrackr.Chat.Api/Middleware/ConversationPersistenceMiddleware.cs
Issue: User messages pass to Claude without injection pattern detection. Reporting.Api has a blocklist but Chat.Api relies solely on system prompt boundaries.
Remediation: Add PromptInjectionMiddleware to Chat.Api scanning user messages before LLM invocation.
MEDIUM — ASI01: Shallow injection blocklist in Reporting.Api
File: src/Biotrackr.Reporting.Api/Biotrackr.Reporting.Api/Validation/ReportRequestValidator.cs, lines 15-21
Issue: Blocklist is trivially bypassed with Unicode homoglyphs, Base64 encoding, or indirect injection via sourceDataSnapshot (not scanned).
Remediation: Add input normalization before matching. Scan sourceDataSnapshot string fields. Consider LLM-based classifier.
MEDIUM — ASI03: Chat.Api conversation endpoints unauthenticated
File: src/Biotrackr.Chat.Api/Biotrackr.Chat.Api/Extensions/EndpointRouteBuilderExtensions.cs, lines 13-29
Issue: /conversations GET, GET/{sessionId}, DELETE/{sessionId} have no .RequireAuthorization(). Any caller can list/read/delete conversation history.
Remediation: Add .RequireAuthorization() to all conversation endpoints.
MEDIUM — ASI05: Post-hoc code validation only warns, doesn't abort
File: src/Biotrackr.Reporting.Api/Biotrackr.Reporting.Api/Services/ReportGenerationService.cs, lines 326-330
Issue: ValidateGeneratedCode logs a warning when dangerous patterns are found but does not abort the job or skip artifact upload.
Remediation: Fail the job when dangerous patterns are detected in the secondary scan.
LOW — ASI02: Tool whitelist logs but doesn't block
File: src/Biotrackr.Chat.Api/Biotrackr.Chat.Api/Middleware/ToolPolicyMiddleware.cs, lines 48-54
Issue: Unrecognized tool calls are logged as warnings but execution continues. Only budget exhaustion triggers blocking.
Remediation: Set blocked = true when tool name is not in AllowedToolNames.
LOW — ASI04: Preview package dependencies
File: src/Biotrackr.Chat.Api/Biotrackr.Chat.Api/Biotrackr.Chat.Api.csproj
Issue: Several packages use -preview and -rc versions with no LTS support.
Remediation: Track for GA releases. Consider packages.lock.json for reproducible builds.
2. CI/CD Security
Scope: .github/workflows/, infra/
Strong Practices ✅
SHA-pinned actions (one exception), OIDC auth, CodeQL scanning, scoped per-job permissions, no pull_request_target abuse, no script injection vectors, secrets via Key Vault.
HIGH — Overly Permissive RBAC: Contributor Role on ACS
File: infra/modules/communication/acs-email.bicep, lines 29, 70-75
Issue: Assigns Contributor role (b24988ac-6180-42a0-ab88-20f7382dd24c) to the managed identity over ACS. Contributor grants full management rights except RBAC assignment.
Remediation: Use a scoped built-in role or custom role with only email-sending permissions.
MEDIUM — Unpinned Action
File: .github/workflows/copilot-setup-steps.yml, line 22
Issue: actions/checkout@v6 uses a mutable tag. All other workflows correctly pin to SHA.
Remediation: Pin to full SHA: actions/checkout@<sha> # v6
MEDIUM — Container Apps Default to Public Ingress
File: infra/modules/host/container-app-http.bicep, line 61
Issue: external: true is hardcoded with no parameter override. APIs behind APIM should use internal ingress.
Remediation: Parameterize external so internal services can disable public exposure.
MEDIUM — AI Foundry Public Network Access
File: infra/modules/ai/foundry.bicep, line 59
Issue: publicNetworkAccess: 'Enabled' exposes AI Foundry endpoint publicly.
Remediation: Set to 'Disabled' with private endpoints, or parameterize per environment.
LOW — Unnecessary Permissions on Build Workflow
File: .github/workflows/build-copilot-python-image.yml, lines 6-11
Issue: pull-requests: write and checks: write granted for a workflow_dispatch-only workflow that doesn't use them.
Remediation: Remove unused permissions.
LOW — Log Analytics Public Network Access
File: infra/modules/monitoring/log-analytics.bicep, lines 29-30
Issue: Both ingestion and query public access enabled. Acceptable for dev but should be restricted in production.
Remediation: Parameterize for environment-specific control.
3. Container Security
Scope: All 14 Dockerfiles in src/
Strong Practices ✅
Multi-stage builds (3 stages), non-root user (USER $APP_UID), COPY-only (no ADD), no secrets in layers, no package installation, exec-form ENTRYPOINT.
MEDIUM — Unpinned Base Image Tags
Files: All 14 Dockerfiles, lines 4 and 10/12
Example: FROM mcr.microsoft.com/dotnet/aspnet:10.0
Issue: Images use :10.0 without SHA256 digest. Builds are non-reproducible.
Remediation: Pin to digest: FROM mcr.microsoft.com/dotnet/aspnet:10.0@sha256:<hash> or full patch version.
MEDIUM — No HEALTHCHECK Directive
Files: All 14 Dockerfiles
Issue: No HEALTHCHECK instruction. Container orchestrators cannot detect unhealthy apps without external probes.
Remediation: Add HEALTHCHECK --interval=30s --timeout=5s CMD curl -f (localhost/redacted) || exit 1
LOW — Unnecessary Port Exposure (8081)
Files: 7 of 14 Dockerfiles (Activity.Api, Chat.Api, Food.Api, Mcp.Server, UI, Vitals.Api, Sleep.Api)
Issue: EXPOSE 8081 alongside 8080. If TLS is terminated at ingress, port 8081 is unnecessary.
Remediation: Remove EXPOSE 8081 unless the app explicitly binds HTTPS at container level.
LOW — Missing .dockerignore
Files: 5 services — Chat.Api, Mcp.Server, Reporting.Api, Reporting.Svc, UI
Issue: Without .dockerignore, COPY . . sends unnecessary files to the Docker daemon build context.
Remediation: Copy .dockerignore from sibling services (e.g., Activity.Api/.dockerignore).
Priority Remediation Roadmap
| Priority |
Finding |
Effort |
Recurring? |
| P1 |
ASI03: Add auth to conversation endpoints |
Low |
New |
| P1 |
HIGH: Scope ACS RBAC to least privilege |
Low |
Recurring |
| P2 |
ASI05: Fail job on dangerous code detection |
Low |
New |
| P2 |
ASI02: Block unrecognized tool calls |
Low |
New |
| P2 |
Pin copilot-setup-steps.yml checkout action |
Low |
New |
| P3 |
ASI01: Add injection middleware to Chat.Api |
Medium |
Recurring |
| P3 |
Parameterize container app ingress |
Medium |
Recurring |
| P3 |
Pin Dockerfile base images by digest |
Medium |
Recurring |
| P4 |
Add HEALTHCHECK to Dockerfiles |
Low |
Recurring |
| P4 |
Add .dockerignore to 5 services |
Low |
Recurring |
| P4 |
Disable AI Foundry public access |
Low |
Recurring |
Generated by Weekly OWASP Security Scan — Multi-Persona · ● 5.8M · ◷
Scan Summary
Comparison with Previous Scan (#341 — 2026-05-07)
Key improvements since last scan:
:10.0not:latest)adminUserEnabledHIGH finding not detected this scan (may be resolved)1. Agentic Security (ASI01-ASI10)
Scope:
src/Biotrackr.Chat.Api/,src/Biotrackr.Mcp.Server/,src/Biotrackr.Reporting.Api/Controls Passing ✅
MEDIUM — ASI01: Chat.Api user messages not injection-scanned
File:
src/Biotrackr.Chat.Api/Biotrackr.Chat.Api/Middleware/ConversationPersistenceMiddleware.csIssue: User messages pass to Claude without injection pattern detection. Reporting.Api has a blocklist but Chat.Api relies solely on system prompt boundaries.
Remediation: Add
PromptInjectionMiddlewareto Chat.Api scanning user messages before LLM invocation.MEDIUM — ASI01: Shallow injection blocklist in Reporting.Api
File:
src/Biotrackr.Reporting.Api/Biotrackr.Reporting.Api/Validation/ReportRequestValidator.cs, lines 15-21Issue: Blocklist is trivially bypassed with Unicode homoglyphs, Base64 encoding, or indirect injection via
sourceDataSnapshot(not scanned).Remediation: Add input normalization before matching. Scan
sourceDataSnapshotstring fields. Consider LLM-based classifier.MEDIUM — ASI03: Chat.Api conversation endpoints unauthenticated
File:
src/Biotrackr.Chat.Api/Biotrackr.Chat.Api/Extensions/EndpointRouteBuilderExtensions.cs, lines 13-29Issue:
/conversationsGET, GET/{sessionId}, DELETE/{sessionId} have no.RequireAuthorization(). Any caller can list/read/delete conversation history.Remediation: Add
.RequireAuthorization()to all conversation endpoints.MEDIUM — ASI05: Post-hoc code validation only warns, doesn't abort
File:
src/Biotrackr.Reporting.Api/Biotrackr.Reporting.Api/Services/ReportGenerationService.cs, lines 326-330Issue:
ValidateGeneratedCodelogs a warning when dangerous patterns are found but does not abort the job or skip artifact upload.Remediation: Fail the job when dangerous patterns are detected in the secondary scan.
LOW — ASI02: Tool whitelist logs but doesn't block
File:
src/Biotrackr.Chat.Api/Biotrackr.Chat.Api/Middleware/ToolPolicyMiddleware.cs, lines 48-54Issue: Unrecognized tool calls are logged as warnings but execution continues. Only budget exhaustion triggers blocking.
Remediation: Set
blocked = truewhen tool name is not inAllowedToolNames.LOW — ASI04: Preview package dependencies
File:
src/Biotrackr.Chat.Api/Biotrackr.Chat.Api/Biotrackr.Chat.Api.csprojIssue: Several packages use
-previewand-rcversions with no LTS support.Remediation: Track for GA releases. Consider
packages.lock.jsonfor reproducible builds.2. CI/CD Security
Scope:
.github/workflows/,infra/Strong Practices ✅
SHA-pinned actions (one exception), OIDC auth, CodeQL scanning, scoped per-job permissions, no
pull_request_targetabuse, no script injection vectors, secrets via Key Vault.HIGH — Overly Permissive RBAC: Contributor Role on ACS
File:
infra/modules/communication/acs-email.bicep, lines 29, 70-75Issue: Assigns Contributor role (
b24988ac-6180-42a0-ab88-20f7382dd24c) to the managed identity over ACS. Contributor grants full management rights except RBAC assignment.Remediation: Use a scoped built-in role or custom role with only email-sending permissions.
MEDIUM — Unpinned Action
File:
.github/workflows/copilot-setup-steps.yml, line 22Issue:
actions/checkout@v6uses a mutable tag. All other workflows correctly pin to SHA.Remediation: Pin to full SHA:
actions/checkout@<sha> # v6MEDIUM — Container Apps Default to Public Ingress
File:
infra/modules/host/container-app-http.bicep, line 61Issue:
external: trueis hardcoded with no parameter override. APIs behind APIM should use internal ingress.Remediation: Parameterize
externalso internal services can disable public exposure.MEDIUM — AI Foundry Public Network Access
File:
infra/modules/ai/foundry.bicep, line 59Issue:
publicNetworkAccess: 'Enabled'exposes AI Foundry endpoint publicly.Remediation: Set to
'Disabled'with private endpoints, or parameterize per environment.LOW — Unnecessary Permissions on Build Workflow
File:
.github/workflows/build-copilot-python-image.yml, lines 6-11Issue:
pull-requests: writeandchecks: writegranted for aworkflow_dispatch-only workflow that doesn't use them.Remediation: Remove unused permissions.
LOW — Log Analytics Public Network Access
File:
infra/modules/monitoring/log-analytics.bicep, lines 29-30Issue: Both ingestion and query public access enabled. Acceptable for dev but should be restricted in production.
Remediation: Parameterize for environment-specific control.
3. Container Security
Scope: All 14 Dockerfiles in
src/Strong Practices ✅
Multi-stage builds (3 stages), non-root user (
USER $APP_UID), COPY-only (no ADD), no secrets in layers, no package installation, exec-form ENTRYPOINT.MEDIUM — Unpinned Base Image Tags
Files: All 14 Dockerfiles, lines 4 and 10/12
Example:
FROM mcr.microsoft.com/dotnet/aspnet:10.0Issue: Images use
:10.0without SHA256 digest. Builds are non-reproducible.Remediation: Pin to digest:
FROM mcr.microsoft.com/dotnet/aspnet:10.0@sha256:<hash>or full patch version.MEDIUM — No HEALTHCHECK Directive
Files: All 14 Dockerfiles
Issue: No
HEALTHCHECKinstruction. Container orchestrators cannot detect unhealthy apps without external probes.Remediation: Add
HEALTHCHECK --interval=30s --timeout=5s CMD curl -f (localhost/redacted) || exit 1LOW — Unnecessary Port Exposure (8081)
Files: 7 of 14 Dockerfiles (Activity.Api, Chat.Api, Food.Api, Mcp.Server, UI, Vitals.Api, Sleep.Api)
Issue:
EXPOSE 8081alongside 8080. If TLS is terminated at ingress, port 8081 is unnecessary.Remediation: Remove
EXPOSE 8081unless the app explicitly binds HTTPS at container level.LOW — Missing .dockerignore
Files: 5 services — Chat.Api, Mcp.Server, Reporting.Api, Reporting.Svc, UI
Issue: Without
.dockerignore,COPY . .sends unnecessary files to the Docker daemon build context.Remediation: Copy
.dockerignorefrom sibling services (e.g.,Activity.Api/.dockerignore).Priority Remediation Roadmap
copilot-setup-steps.ymlcheckout action