Skip to content
masahiroidPublic

About

Evidence-based SBOM vulnerability matching, license policy checks, JS/TS static analysis and customer Word reports

Topics

Resources

Contributing

Security policy

Stars

2 stars

Watchers

0 watching

Forks

Repository files navigation

SecuLens

English | 日本語

SecuLens is a TypeScript security assessment CLI and library. It reads SPDX and CycloneDX SBOMs, independently matches component versions against OSV advisory records, evaluates license policies, reviews JavaScript/TypeScript syntax trees, and writes customer-facing Word reports.

Version 1.1.0. Findings are evidence for review, not a guarantee of security or legal compliance. The independent Python implementation is available at https://github.com/masahiroid/seculens-python; the independent PHP implementation is also available.

Interactive wizard

Run seculens with no arguments to start interactive setup. English is the default: press Enter at the language prompt, or type ja for Japanese. Use seculens wizard --lang ja to open Japanese setup directly.

seculens
# or
seculens wizard --lang ja

Choose an existing SBOM assessment or SBOM generation, then supply the requested paths and options. Assessment asks for a local OSV snapshot or explicit OSV fetching, an optional license policy and source directory, customer / target / preparer, report style, output directory and findings exit policy. Customer report layout is the wizard default. Review the settings and confirm to start. EOF or choosing n at the final prompt cancels; Ctrl+C interrupts. OSV fetching sends package names and ecosystems; the wizard displays this before execution.

Install

Requires Node.js 22.12 or later and npm.

npm install -g seculens
seculens --help

Release archives are also available from GitHub releases.

Assess an existing SBOM

Offline assessment with a local OSV JSON snapshot:

seculens scan sbom.json --db database.json --policy policy.json \
  --customer 'Example Customer' --lang ja --output reports

Download candidate advisories and match locally:

seculens scan sbom.json --fetch-osv --policy policy.json --output reports

--fetch-osv sends package names and ecosystems to api.osv.dev. Package versions are matched by SecuLens, not delegated to the OSV query service. Source code and the entire SBOM are not uploaded. This option requires network access; there is no network access in --db mode. Network failures stop the assessment instead of producing a clean result.

Every assessment saves report.json, report.docx, the original sbom.json, and database.json. Reports include database and SBOM SHA-256 digests so the evidence can be retained and reused. Replaying a snapshot stabilizes findings; report timestamps and generated DOCX metadata can differ.

Generate an SBOM

For an npm project with its dependencies already installed:

seculens sbom ./my-project --format cyclonedx --output sbom.json
seculens sbom ./my-project --format spdx --output sbom.spdx.json

This invokes the existing npm sbom command without running installation scripts. For Python, PHP, containers or other targets, generate an SBOM with your existing tool and import it into SecuLens. npm must support npm sbom.

Optional JS and TS review & supply chain inspection

seculens scan sbom.json --db database.json --source ./src --output reports

Rules flag direct eval, new Function, assignments to innerHTML/outerHTML, functions exceeding cyclomatic complexity 10 or nesting depth 4, as well as supply-chain risk patterns: child process execution (child_process), environment variable access (process.env), and sensitive credential path references (~/.ssh, ~/.aws, ~/.npmrc). Additionally, lifecycle scripts (preinstall, install, postinstall) declared in package.json or dependency entries in package-lock.json are reported as security candidates. Logical &&, ||, and ?? contribute to complexity. Nested functions are measured separately. Syntax errors appear as coverage findings. Generated directories and symlinks are skipped.

These are syntax- and metadata-based review candidates. There is no interprocedural dataflow, type-based call resolution, exploitability determination, or Python/PHP AST analysis in this release. Shadowed names can produce candidates requiring manual review; other unsafe constructs can be missed.

License policy

{
  "allow": ["MIT", "Apache-2.0", "BSD-3-Clause", "ISC"],
  "deny": ["AGPL-3.0-only", "AGPL-3.0-or-later"]
}

SPDX expressions are parsed structurally. AND requires all branches to be allowed; OR accepts an allowed choice. A WITH exception must be explicitly allowed as the complete expression. Unknown, custom or missing licenses require review. Declared licenses are not verified against source files, distribution obligations or the customer's actual use. No policy means all licenses require review.

Prioritization

Add an optional context to the policy file to rank vulnerabilities for one environment. Without it, reports have no priority. Severity and CVSS scores never change.

{
  "allow": ["MIT"],
  "context": {
    "defaults": { "exposure": "internal", "justification": "Runs on the private network" },
    "components": [
      { "name": "lodash", "ecosystem": "npm", "reachability": "not-reachable", "justification": "Only used by build scripts" }
    ]
  }
}

Each finding starts from a baseline: Critical is P1, High and Unrated are P2, Medium is P3, Low and None are P4. Each stated factor then moves it one level, within P1 to P4. None stays P4.

Factor Raises No change Lowers
exposure internet internal isolated
reachability reachable unknown not-reachable
criticality high medium low

The first components entry that matches the package name (and ecosystem, if given) and states a factor wins; otherwise defaults applies. Every entry requires a justification. Each finding records the factors used, their effect, source and justification in priority, and the Word report shows them. SecuLens does not verify these statements, so a priority does not establish exploitability.

Supported input and matching

  • SPDX 2.2 and 2.3 JSON package records.
  • CycloneDX 1.4 through 1.7 JSON component and dependency records.
  • npm versions: SemVer.
  • PyPI versions: PEP 440; package names are normalized.
  • Packagist versions follow Composer normalization: leading v, one to four numeric parts, build metadata ignored, and stability suffixes ordered dev < alpha (a) < beta (b) < RC < stable < patch (pl, p). Branch versions (dev-main, 1.x-dev) remain unassessed.
  • OSV SEMVER and ECOSYSTEM ranges, explicit affected versions, fixed/last-affected/limit boundaries and withdrawn records. GIT-only ranges are unassessed. Equivalent advisory aliases are merged per component.

A supported package URL (pkg:npm, pkg:pypi, pkg:composer) and version are required. Other ecosystems are recorded as unassessed. Input adapters validate fields used by SecuLens; they are not complete standards conformance validators. SPDX 3, XML, cryptographic attestation verification, customer-specific risk prioritization, source license discovery, and infrastructure configuration audits are not supported yet.

“No match” means no matching advisory in the supplied snapshot, not that a component is safe. An offline snapshot must contain the relevant records; SecuLens cannot prove its completeness. A supported version range provides package-level evidence, not proof that vulnerable code is reachable.

Schema validation

seculens validate sbom.json                 # SPDX 2.2/2.3 or CycloneDX 1.4–1.7 JSON
seculens validate report.json --kind report # SecuLens report schema 1.1

Validation runs offline against the official schemas bundled in schemas/ (see its README for sources, hashes and licenses). Output is JSON {valid, schema, errors[]}. Exit code 0 means valid; 2 means invalid, an unsupported version, or an input error. Schema validation checks structure and formats only; it does not prove an SBOM is complete or that findings are correct.

Exit codes

  • 0: assessment completed without incomplete coverage. Review findings may still exist.
  • 1: --fail-on-findings was set and affected vulnerabilities, denied licenses or security candidates exist.
  • 2: invalid input, operational failure, or incomplete coverage. With --fail-on-findings, detected findings take precedence over incomplete coverage.

Use the JSON report for detailed checks. Word output is English by default; --lang ja localizes its main headings and overview. Advisory content and technical notes retain their original language.

Library API

import { scanSbom, validateDatabase, writeWordReport } from "seculens";

const records = validateDatabase(databaseJson);
const report = scanSbom(sbomText, records, {
  customer: "Example Customer",
  policy: { allow: ["MIT", "Apache-2.0"] },
});
await writeWordReport(report, "report.docx", "ja");

Development

npm ci
npm test
npm pack

See architecture and roadmap for the independent implementations and future work. See security policy for responsible reporting.

License

Apache-2.0. SecuLens is independent of Trivy and of the optical lens company using the SECULENS name. Advisory records retain their respective source licensing; do not assume the software license applies to downloaded database snapshots.

Japanese Word reports embed the bundled Noto Sans JP font (SIL OFL 1.1) to preserve Japanese text across viewing environments. This increases the report size by approximately 4 MB.

Customer report mode

Add --report-style customer to generate a formal Word report with a dedicated cover, executive summary, severity colors, a prioritized findings register, numbered details, component coverage tables, evidence hashes and page numbers. Existing standard layout remains available with --report-style standard (the default).

seculens scan bom.json --db database.json --policy policy.json \
  --customer "Customer Company" --target "Customer Web Service" \
  --issuer "Security Assessment Team" --lang ja \
  --report-style customer --output reports/customer

--target supplies a human-readable system name; it defaults to the SBOM filename. --issuer supplies the cover's preparer and document author. Both are optional. The report ID incorporates the SBOM hash, DB hash and assessment timestamp. Finding numbers link the register to details; code/license review statuses are separate from vulnerability severity.

Severity colors: Critical / High red, Medium amber, Low blue, None green, Unrated gray. Labels accompany colors for accessibility. Vulnerability counts consolidate aliases per component; category counts include review candidates. CVSS zero / None is a severity band, not proof of absence of vulnerabilities.

Severity comes from validated CVSS 3.0/3.1 base vectors, CVSS 4.0 vectors or recognized database_specific.severity labels. Package-specific OSV affected.severity overrides global vectors for that affected entry. Alias consolidation preserves all provenance and displays the highest supported severity; when sources disagree, the underlying labels/vectors and scores remain available in JSON. CVSS 2 vectors and malformed vectors are not calculated. Without other usable metadata these stay Unrated. No severity is inferred from advisory wording, AST review candidates or licenses.

Report JSON schema 1.2 adds optional priority to findings. Schema 1.1 added optional vulnerability severity (level, optional base score, and source record IDs / field paths / raw values) and optional CLI sourceAnalysis execution metadata. Presentation sorting does not alter the assessment JSON. Word contains concise severity attribution; full original metadata and references stay in JSON. This mode changes presentation and adds severity evidence, not the vulnerability matching criteria.

Scoring reference: https://www.first.org/cvss/v3.1/specification-document OSV field reference: https://ossf.github.io/osv-schema/

await writeWordReport(report, "customer.docx", "ja", {
  style: "customer",
  issuer: "Assessment Team",
});

About

Evidence-based SBOM vulnerability matching, license policy checks, JS/TS static analysis and customer Word reports

Topics

Resources

Contributing

Security policy

Stars

2 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages