Skip to main content

Database schema discovery

Every scan maps your application's database schema from the ORM models and migrations in the repository. Vulkro reads code only and never connects to a database.

vulkro scan . --format json # see the top-level "schema" object

There is no separate schema command: the schema is part of every scan.

Where you see it​

  • JSON output: the top-level schema object (absent when no schema is found). The NDJSON summary line carries the counts.
  • Local console: the schema of a saved scan (GET /api/scans/<id>/schema).
  • Vulkro Cloud: each code repository has a Database area with Tables, Columns (filterable by sensitivity) and a Relationships diagram.

The schema also feeds the data-flow map: a flow that touches a table takes its data classes from that table's columns.

What it reads​

StackSources
JavaScript / TypeScriptPrisma, Drizzle, Mongoose (including NestJS @Schema), TypeORM, MikroORM, Sequelize, Knex migrations
PythonDjango models, SQLAlchemy and SQLModel, Alembic migrations
JavaJPA / Hibernate @Entity classes
GoGORM structs, ent schemas
OtherSQL DDL migrations, Rails db/schema.rb and migrations, EF Core, Laravel migrations

A table found in both models and migrations becomes one entry. In a monorepo, a table's id is <package dir>#<name>, so two packages with a users table stay separate.

What each table carries​

  • Columns: type, nullability, keys, unique, default, enum values, foreign keys.
  • Sensitivity: none, pii, health, financial, secret or credential, matched on whole words in the column name.
  • Protection: hashed or encrypted, when the code shows it.
  • Hints: soft-delete, tenant, owner and timestamp columns.
  • Endpoints that read or write the table, with method, path and whether they need sign-in.

Schema rules​

RuleSeverityFires when
schema-plaintext-password-columnHighA password column is written with no hashing on any write path.
schema-plaintext-secret-columnMediumA token, API key or secret column is written raw.
schema-login-identifier-not-uniqueMediumThe email or username used to look up accounts is not unique.
schema-tenant-column-missingMediumMost tables have a tenant column, but a sensitive one has none and no key to a tenant-scoped table.

Two schema facts add context to existing findings without changing severity or confidence: schema-sensitive-table-unauthenticated (a missing-auth finding whose endpoint reaches sensitive data) and schema-privileged-columns (a mass-assignment finding that writes role, admin, balance, owner or tenant columns).

Limits​

A column added by hand in production and never written in the repository is not seen. Sensitivity is name-based: a column called notes that holds health data is not flagged.

See also: Secrets