Thanks to visit codestin.com
Credit goes to github.com

Skip to content

[Bug]: 13 security & UI issues found via code review + live site inspection #130

@jay-cyble

Description

@jay-cyble

Describe the bug

A source code review of the full monorepo and a browser inspection of the live demo at tryaisoc.com surfaced 13 bugs — all fixable with minimal code changes (1–5 lines each), no infrastructure or migration work required.

Note: I'd like to pick up the implementation for these fixes once this issue has been reviewed and verified by the repo owner. Happy to submit PRs for whichever items are confirmed.


1. Unauthenticated EASM /scan endpoint

Steps to reproduce: Send a POST to /api/v1/easm/scan with a ScanRequest body containing any tenant_id — no auth header needed.

Expected behavior: The endpoint should require authentication like the neighboring /assets and /drift endpoints in the same file.

Actual behavior: No Depends(get_current_user) guard exists, so any unauthenticated caller can trigger EASM discovery scans against any tenant using the operator's Shodan/Censys API keys.

Component: services/api/app/api/v1/endpoints/easm.py


2. EASM /assets and /drift cross-tenant data access

Steps to reproduce: Authenticate as user in tenant A, then call GET /api/v1/easm/assets?tenant_id=<tenant_B_id>.

Expected behavior: Request should be rejected or scoped to the caller's own tenant.

Actual behavior: The endpoint uses effective_tenant = tenant_id or current_user.tenant_id without verifying ownership, so any authenticated user can read another tenant's external assets and drift events.

Component: services/api/app/api/v1/endpoints/easm.py


3. .env.example contains a working Fernet encryption key

Steps to reproduce: Copy .env.example to .env as instructed by the README, then inspect AISOC_CREDENTIAL_KEY.

Expected behavior: The example file should contain a placeholder prompting the operator to generate their own key.

Actual behavior: A valid, base64-encoded Fernet key is shipped. Operators who don't rotate it encrypt all connector credentials under a publicly-known key — anyone with DB access can decrypt stored API tokens, OAuth secrets, and service account keys.

Component: .env.example


4. Database exception details exposed to API clients

Steps to reproduce: Trigger a database error on any of the affected endpoints (e.g., by sending malformed data to knowledge base, compliance, or case endpoints).

Expected behavior: A generic error message like "Internal database error" should be returned.

Actual behavior: Raw Postgres exception messages including table names, column names, constraint names, and SQL fragments are returned via raise HTTPException(detail=f"Database error: {exc}"). Approximately 8 occurrences across knowledge_base.py, compliance.py, and cases.py.

Component: services/api


5. ITSM webhook broken — wrong column name in SQL

Steps to reproduce: Send a webhook payload to the ITSM inbox endpoint.

Expected behavior: The webhook should be processed successfully.

Actual behavior: Raw SQL query references column enabled but the ORM model defines it as is_enabled, causing a runtime ProgrammingError on every call. The entire ITSM webhook integration is non-functional.

Component: services/api/app/api/v1/endpoints/inbox_itsm.py


6. Marketplace endpoint missing path traversal guard

Steps to reproduce: If the marketplace index JSON contains a relative path like ../../etc/passwd, the _resolve_item_path function resolves it without checking bounds.

Expected behavior: Resolved paths should be validated to stay within the repository root via is_relative_to().

Actual behavior: After .resolve(), there is no bounds check, so a manipulated index entry could serve files outside the repo directory.

Component: services/api/app/api/v1/endpoints/marketplace.py


7. Login page open redirect

Steps to reproduce: Navigate to /login?next=https://evil.com, then log in.

Expected behavior: The next parameter should only accept relative paths.

Actual behavior: The value is passed directly to router.replace(next) without validation, enabling phishing attacks where users are redirected to attacker-controlled sites after login.

Component: apps/web/src/app/login/page.tsx


8. GraphQL search vulnerable to wildcard DoS

Steps to reproduce: Send a GraphQL query with search set to %_%_%_%_%_%_%_%_%_%_%_.

Expected behavior: Wildcard characters in user input should be escaped before use in ilike patterns.

Actual behavior: Alert.title.ilike(f"%{search}%") passes unescaped user input, allowing crafted patterns that force expensive full-table scans on the database.

Component: services/api/app/graphql/query.py


9. Prometheus metrics cardinality bomb

Steps to reproduce: Generate traffic to endpoints with dynamic path segments (e.g., /api/v1/connectors/{uuid}), then check Prometheus memory usage over time.

Expected behavior: Metrics should use route templates (e.g., /api/v1/connectors/{connector_id}) for labels.

Actual behavior: endpoint = request.url.path uses raw URLs including UUIDs, creating an unbounded number of time series that grow monotonically and eventually cause OOM.

Component: services/api/app/main.py


10. Insecure default values for internal auth tokens

Steps to reproduce: Deploy without setting REALTIME_INTERNAL_TOKEN, JWT_SECRET, or alert_webhook_secret environment variables.

Expected behavior: The application should fail to start with a clear error if critical secrets are missing.

Actual behavior: These fall back to "changeme" or "changeme-insecure-default", effectively bypassing inter-service authentication and JWT signing if operators don't explicitly configure them.

Component: services/agents/app/playbook/engine.py, services/api/app/auth/oidc.py, services/api/app/auth/saml.py, services/honeytokens/app/core/config.py


11. Duplicate site name in browser tab titles

Steps to reproduce: Visit any console page (e.g., /dashboard, /alerts) and check the browser tab title.

Expected behavior: Dashboard | AiSOC

Actual behavior: Dashboard | AiSOC | AiSOC — the Next.js metadata.title.template is doubling the site name on every console page.

Component: Root layout metadata in apps/web


12. Missing page titles on /honeytokens and /purple-team

Steps to reproduce: Navigate to /honeytokens or /purple-team and check the browser tab title.

Expected behavior: Page-specific titles like Honeytokens | AiSOC.

Actual behavior: Both fall back to the generic homepage title AiSOC -- Open-Source AI Security Operations Center because they're missing their metadata.title export.

Component: apps/web/src/app/(console)/honeytokens/page.tsx, apps/web/src/app/(console)/purple-team/page.tsx


13. Inconsistent title separator characters across pages

Steps to reproduce: Compare browser tab titles across different console pages.

Expected behavior: All pages should use the same separator convention.

Actual behavior: Some pages use | (e.g., Dashboard | AiSOC) while others use -- (e.g., Detection Catalog -- AiSOC).

Component: Various page metadata exports across apps/web


AiSOC version

v7.3.1 (commit 182afc5b, main branch)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions