or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

examples

edge-cases.mdreal-world-scenarios.md
index.md
tile.json

validate-integrity.mddocs/reference/

Integrity Hash Validation

The ValidateIntegrity class validates that package integrity hashes use SHA-512 algorithm for maximum security.

Capabilities

ValidateIntegrity Constructor

Creates a new integrity hash validator instance.

/**
 * Creates a new integrity hash validator
 * @param {Object} options - Validator configuration
 * @param {Object} options.packages - Package object from parsed lockfile
 * @throws {Error} If packages is not provided or not an object
 */
class ValidateIntegrity {
  constructor(options: {
    packages: Object;
  });
}

Requirements: The packages parameter must be an object (typically from ParseLockfile.parseSync().object). Throws an error if not provided or not an object.

Usage Examples:

const { ValidateIntegrity, ParseLockfile } = require('lockfile-lint-api');

// Parse lockfile first
const parser = new ParseLockfile({ lockfilePath: './package-lock.json' });
const lockfile = parser.parseSync();

// Create validator
const validator = new ValidateIntegrity({ packages: lockfile.object });

Validate Integrity Hashes

Validates that all packages in the lockfile use SHA-512 integrity hashes.

/**
 * Validates all packages use SHA-512 integrity hashes
 * @param {Object} [options] - Validation options
 * @param {string[]} [options.integrityExclude] - Array of package names to exclude from validation
 * @returns {Object} Validation result with type ('success' or 'error') and errors array
 * @throws {Error} If integrityExclude is provided but not an array
 */
validate(options?: {
  integrityExclude?: string[];
}): {
  type: 'success' | 'error';
  errors: Array<{
    message: string;
    package: string;
  }>;
}

Behavior:

  • Checks that all package integrity hashes use sha512 algorithm
  • Packages without an integrity field are automatically skipped (e.g., git dependencies)
  • Packages in the integrityExclude list are skipped
  • Returns error result if any package uses a weaker hash algorithm (e.g., sha1, sha256)

Integrity Hash Format:

npm integrity hashes follow the Subresource Integrity (SRI) format:

<algorithm>-<base64-hash>

Examples:

  • sha512-ABC123... (recommended)
  • sha256-ABC123... (weaker)
  • sha1-ABC123... (weak, deprecated)

Usage Examples:

const { ValidateIntegrity, ParseLockfile } = require('lockfile-lint-api');

// Basic usage - validate all packages
const parser = new ParseLockfile({ lockfilePath: './package-lock.json' });
const lockfile = parser.parseSync();
const validator = new ValidateIntegrity({ packages: lockfile.object });

const result = validator.validate();

if (result.type === 'success') {
  console.log('All packages use SHA-512 integrity hashes');
} else {
  console.error('Integrity validation failed:');
  result.errors.forEach(error => {
    console.error(`  ${error.package}: ${error.message}`);
  });
}

Exclude Specific Packages:

const { ValidateIntegrity, ParseLockfile } = require('lockfile-lint-api');

const parser = new ParseLockfile({ lockfilePath: './package-lock.json' });
const lockfile = parser.parseSync();
const validator = new ValidateIntegrity({ packages: lockfile.object });

// Exclude legacy packages that can't be updated
const result = validator.validate({
  integrityExclude: ['legacy-package', 'old-dependency', '@company/legacy-lib']
});

if (result.type === 'error') {
  console.error('Non-excluded packages have weak integrity hashes:');
  result.errors.forEach(error => console.error(error.message));
}

CI/CD Integration:

const { ValidateIntegrity, ParseLockfile } = require('lockfile-lint-api');

function validateIntegrityInPipeline(lockfilePath) {
  try {
    const parser = new ParseLockfile({ lockfilePath });
    const lockfile = parser.parseSync();
    const validator = new ValidateIntegrity({ packages: lockfile.object });
    const result = validator.validate();

    if (result.type === 'error') {
      console.error('Build failed: Weak integrity hashes detected!');
      result.errors.forEach(error => {
        console.error(`  Package: ${error.package}`);
        console.error(`  ${error.message}`);
      });
      return false;
    }

    console.log('✓ All packages use strong SHA-512 integrity hashes');
    return true;
  } catch (error) {
    console.error('Validation error:', error.message);
    return false;
  }
}

if (!validateIntegrityInPipeline('./package-lock.json')) {
  process.exit(1);
}

Validate Single Package

Validates a single package's integrity hash.

/**
 * Validates a single package's integrity hash
 * @param {string} packageName - Package key from the lockfile (e.g., 'lodash@4.17.21')
 * @returns {boolean} True if package uses SHA-512 or has no integrity field, false otherwise
 */
validateSingle(packageName: string): boolean;

Behavior:

  • Returns true if the package's integrity hash uses sha512 algorithm
  • Returns true if the package has no integrity field
  • Returns false if the package uses a different hash algorithm

Usage Examples:

const { ValidateIntegrity, ParseLockfile } = require('lockfile-lint-api');

const parser = new ParseLockfile({ lockfilePath: './package-lock.json' });
const lockfile = parser.parseSync();
const validator = new ValidateIntegrity({ packages: lockfile.object });

// Validate specific packages
const isLodashSecure = validator.validateSingle('lodash@4.17.21');
const isReactSecure = validator.validateSingle('react@18.2.0');

if (!isLodashSecure) {
  console.error('lodash uses weak integrity hash');
}

// Check all critical packages
const criticalPackages = [
  'express@4.18.2',
  'jsonwebtoken@9.0.0',
  'bcrypt@5.1.0'
];

criticalPackages.forEach(packageName => {
  if (!validator.validateSingle(packageName)) {
    console.error(`CRITICAL: ${packageName} uses weak integrity hash`);
    process.exit(1);
  }
});

console.log('All critical packages have strong integrity hashes');

Validation Result Structure

The validate() method returns a consistent result object:

interface IntegrityValidationResult {
  type: 'success' | 'error';
  errors: IntegrityValidationError[];
}

interface IntegrityValidationError {
  message: string;  // Detailed error message with expected and actual hash types
  package: string;  // Package name that failed validation
}

Success Example:

{
  type: 'success',
  errors: []
}

Error Example:

{
  type: 'error',
  errors: [
    {
      message: 'detected invalid integrity hash type for package: old-package@1.0.0\n    expected: sha512\n    actual: sha1-XYZ789...\n',
      package: 'old-package@1.0.0'
    }
  ]
}

Security Use Cases

Integrity hash validation ensures package authenticity and prevents tampering:

  1. Prevent Package Tampering: Detect if package contents have been modified
  2. Algorithm Strength: Ensure cryptographically strong hashes (SHA-512)
  3. Compliance Requirements: Meet security standards requiring strong hashes
  4. Supply Chain Security: Verify package integrity throughout the supply chain
  5. Legacy Package Detection: Identify packages using deprecated hash algorithms

Why SHA-512?

  • SHA-1: Deprecated - Cryptographically broken, collision attacks possible
  • SHA-256: Weak - Faster to compute, more vulnerable to brute force
  • SHA-512: Strong - More secure, recommended by security standards

Security Audit Example:

const { ValidateIntegrity, ParseLockfile } = require('lockfile-lint-api');

function auditIntegrityHashes(lockfilePath) {
  const parser = new ParseLockfile({ lockfilePath });
  const lockfile = parser.parseSync();

  const stats = {
    total: 0,
    withIntegrity: 0,
    sha512: 0,
    weak: []
  };

  for (const [packageName, metadata] of Object.entries(lockfile.object)) {
    stats.total++;

    if (metadata.integrity) {
      stats.withIntegrity++;
      const algorithm = metadata.integrity.split('-')[0];

      if (algorithm === 'sha512') {
        stats.sha512++;
      } else {
        stats.weak.push({
          package: packageName,
          algorithm: algorithm
        });
      }
    }
  }

  console.log('Integrity Hash Audit Results:');
  console.log(`  Total packages: ${stats.total}`);
  console.log(`  With integrity: ${stats.withIntegrity}`);
  console.log(`  Using SHA-512: ${stats.sha512}`);
  console.log(`  Using weak hashes: ${stats.weak.length}`);

  if (stats.weak.length > 0) {
    console.log('\nPackages with weak hashes:');
    stats.weak.forEach(({ package: pkg, algorithm }) => {
      console.log(`  ${pkg} (${algorithm})`);
    });
  }

  return stats.weak.length === 0;
}

if (!auditIntegrityHashes('./package-lock.json')) {
  console.error('\nAudit failed: Weak integrity hashes detected');
  process.exit(1);
}

Package Exclusion

The integrityExclude option allows excluding specific packages from validation:

Use Cases for Exclusion:

  1. Legacy Dependencies: Old packages that can't be updated
  2. Git Dependencies: Packages installed from git (no integrity by default)
  3. Local Development: Temporary exclusions during development
  4. Gradual Migration: Phased approach to improving security

Exclusion Format:

Package names should match the prefix of the package key in the lockfile:

  • Simple package: 'lodash' matches 'lodash@4.17.21'
  • Scoped package: '@babel/core' matches '@babel/core@7.20.0'

Usage Examples:

const { ValidateIntegrity, ParseLockfile } = require('lockfile-lint-api');

const parser = new ParseLockfile({ lockfilePath: './package-lock.json' });
const lockfile = parser.parseSync();
const validator = new ValidateIntegrity({ packages: lockfile.object });

// Exclude multiple packages
const result = validator.validate({
  integrityExclude: [
    'legacy-package',
    'old-dependency',
    '@company/legacy-lib',
    '@types/old-types'
  ]
});

// Exclude all packages from a specific scope
const scopedExclusions = [
  '@legacy/package-a',
  '@legacy/package-b',
  '@legacy/package-c'
];

const result2 = validator.validate({
  integrityExclude: scopedExclusions
});

Progressive Security Enforcement:

const { ValidateIntegrity, ParseLockfile } = require('lockfile-lint-api');

// Start with extensive exclusions, gradually reduce over time
const exclusionConfig = {
  phase1: ['legacy-a', 'legacy-b', 'legacy-c', 'old-dep'],  // Initial
  phase2: ['legacy-a', 'legacy-b'],  // After updates
  phase3: ['legacy-a'],  // Near completion
  phase4: []  // Full enforcement
};

const currentPhase = process.env.SECURITY_PHASE || 'phase1';

const parser = new ParseLockfile({ lockfilePath: './package-lock.json' });
const lockfile = parser.parseSync();
const validator = new ValidateIntegrity({ packages: lockfile.object });

const result = validator.validate({
  integrityExclude: exclusionConfig[currentPhase]
});

if (result.type === 'error') {
  console.error(`Integrity validation failed (${currentPhase}):`);
  result.errors.forEach(error => console.error(error.message));
  process.exit(1);
}

console.log(`✓ Integrity validation passed (${currentPhase})`);

Error Handling

Constructor Errors:

// Throws: 'expecting an object passed to validator constructor'
const validator = new ValidateIntegrity();  // Missing packages
const validator = new ValidateIntegrity({ packages: null });  // Invalid type
const validator = new ValidateIntegrity({ packages: [] });  // Array instead of object

Validation Errors:

const validator = new ValidateIntegrity({ packages: lockfile.object });

// Throws: 'excluded packages must be an array'
validator.validate({ integrityExclude: 'legacy-package' });  // String instead of array
validator.validate({ integrityExclude: { pkg: 'legacy' } });  // Object instead of array

Implementation Notes

  1. Algorithm Detection: Extracts algorithm from integrity field by splitting on - and taking first part
  2. SHA-512 Check: Uses string equality to compare algorithm name
  3. Prefix Matching: Exclusions match package names by prefix (with @ for version delimiter)
  4. Missing Integrity: Packages without integrity field are automatically skipped
  5. Error Tolerance: Parsing errors in integrity field are silently caught

Comprehensive Security Example

Combining integrity validation with other security checks:

const {
  ParseLockfile,
  ValidateIntegrity,
  ValidateHttps,
  ValidateHost,
  ValidatePackageNames
} = require('lockfile-lint-api');

function comprehensiveSecurityValidation(lockfilePath) {
  const parser = new ParseLockfile({ lockfilePath });
  const lockfile = parser.parseSync();

  const validations = [
    {
      name: 'HTTPS Protocol',
      validator: new ValidateHttps({ packages: lockfile.object }),
      validate: () => validator.validate()
    },
    {
      name: 'Allowed Hosts',
      validator: new ValidateHost({ packages: lockfile.object }),
      validate: (v) => v.validate(['npm'])
    },
    {
      name: 'Package Names',
      validator: new ValidatePackageNames({ packages: lockfile.object }),
      validate: (v) => v.validate()
    },
    {
      name: 'Integrity Hashes',
      validator: new ValidateIntegrity({ packages: lockfile.object }),
      validate: (v) => v.validate({
        integrityExclude: ['legacy-package']
      })
    }
  ];

  let allPassed = true;
  const allErrors = [];

  validations.forEach(({ name, validator, validate }) => {
    const result = validate(validator);
    if (result.type === 'error') {
      console.error(`\n✗ ${name} validation failed:`);
      result.errors.forEach(error => {
        console.error(`  ${error.message}`);
        allErrors.push({ validation: name, ...error });
      });
      allPassed = false;
    } else {
      console.log(`✓ ${name} validation passed`);
    }
  });

  if (!allPassed) {
    console.error(`\n${allErrors.length} total validation error(s) found`);
  }

  return allPassed;
}

if (!comprehensiveSecurityValidation('./package-lock.json')) {
  console.error('\nLockfile security validation failed!');
  process.exit(1);
}

console.log('\n✓ All security validations passed');

Hash Algorithm Comparison

AlgorithmStatusSecurity LevelUse Case
SHA-1⚠️ DeprecatedVery WeakNever use
SHA-256⚠️ WeakModerateAvoid if possible
SHA-512✓ RecommendedStrongUse everywhere

Migration Strategy:

If your lockfile contains packages with weak hashes:

  1. Update dependencies: npm update or yarn upgrade
  2. Regenerate lockfile: Delete and reinstall
  3. Use exclusions temporarily for unmaintained packages
  4. Consider replacing unmaintained packages with alternatives

Edge Cases

Handling Missing Integrity Fields

// Packages without integrity field are automatically skipped
{
  'git-package@1.0.0': {
    version: '1.0.0',
    resolved: 'git+https://github.com/user/repo.git'
    // No integrity field - automatically skipped
  }
}

Handling Different Hash Algorithms

// These will fail validation
integrity: 'sha1-ABC123...'
integrity: 'sha256-ABC123...'

// This will pass validation
integrity: 'sha512-ABC123...'

Handling Exclusion Matching

// Exclusion matches by prefix
integrityExclude: ['lodash']  // Matches 'lodash@4.17.21', 'lodash@4.18.0', etc.
integrityExclude: ['@babel/core']  // Matches '@babel/core@7.20.0', '@babel/core@7.21.0', etc.