How to Create Custom Hook Scripts for Package Validation

Advanced 30 minutes DevOps / Platform Engineers Advanced Configuration

Write hook scripts that receive package metadata via environment variables and integrate custom validation logic into the proxy pipeline.

Overview

Chainsaw supports hook scripts — custom executable scripts that run during the package request lifecycle. Hooks receive package metadata as environment variables and can approve, block, or flag requests based on your organization’s custom logic. This allows you to integrate Chainsaw with internal systems, custom blocklists, or proprietary scanning tools.

Prerequisites

  • Admin role in Chainsaw
  • Shell scripting experience (bash, Python, or any executable)
  • Access to the Chainsaw server filesystem (or Docker volume)

Step 1: Understand the Hook Lifecycle

When a package request arrives, Chainsaw can invoke your hook script at the validation phase:

  1. Package request arrives
  2. Built-in checks run (malware, typosquat, policy evaluation)
  3. Hook script executes (if configured)
  4. Hook exit code determines the outcome
  5. Package is served or blocked
Hook script lifecycle in the request pipeline
Hook scripts run after built-in checks and before the package is served

Exit Codes

Exit CodeMeaning
0Allow — package request proceeds
Non-zeroBlock — package request is rejected

Step 2: Available Environment Variables

Chainsaw passes rich context to your hook script via environment variables:

VariableDescriptionExample
CHAINSAW_REPOSITORYRepository namenpmjs
CHAINSAW_PACKAGEPackage namelodash
CHAINSAW_VERSIONPackage version4.17.21
CHAINSAW_FORMATPackage ecosystemnpm
CHAINSAW_CLIENT_IDRequesting client IDabc123
CHAINSAW_CLIENT_TYPEClient typeend-user
Use these environment variables to make decisions based on any combination of package identity, ecosystem, and requesting client.

Step 3: Write a Hook Script

Example 1: Internal Blocklist

Check packages against a custom blocklist file:

#!/bin/bash
# /opt/chainsaw/hooks/blocklist-check.sh

BLOCKLIST="/opt/chainsaw/hooks/blocklist.txt"

# Check if the package is in the blocklist
if grep -q "^${CHAINSAW_FORMAT}/${CHAINSAW_PACKAGE}$" "$BLOCKLIST"; then
    echo "BLOCKED: ${CHAINSAW_PACKAGE} is on the internal blocklist"
    exit 1
fi

exit 0

Blocklist file format:

npm/malicious-package
pip/compromised-lib
maven/org.evil/backdoor
Blocklist hook script
A simple hook script that checks packages against an internal blocklist

Example 2: External Scanning Integration

Call an external vulnerability scanner API:

#!/bin/bash
# /opt/chainsaw/hooks/external-scan.sh

SCAN_API="https://internal-scanner.example.com/api/check"

# Call external scanner
RESULT=$(curl -s -o /dev/null -w "%{http_code}" \
    "${SCAN_API}?ecosystem=${CHAINSAW_FORMAT}&package=${CHAINSAW_PACKAGE}&version=${CHAINSAW_VERSION}")

if [ "$RESULT" = "200" ]; then
    exit 0  # Scanner says OK
elif [ "$RESULT" = "403" ]; then
    echo "BLOCKED: External scanner flagged ${CHAINSAW_PACKAGE}@${CHAINSAW_VERSION}"
    exit 1
else
    echo "WARNING: Scanner unavailable (HTTP $RESULT), allowing package"
    exit 0  # Fail open — adjust to exit 1 if you prefer fail-closed
fi
External scanning hook script
Integrate with an external scanning tool via API

Example 3: Restrict AI Agents to Approved Packages

#!/bin/bash
# /opt/chainsaw/hooks/ai-agent-guard.sh

# Only apply restrictions to AI agent clients
if [ "$CHAINSAW_CLIENT_TYPE" != "ai-agent" ]; then
    exit 0
fi

APPROVED_LIST="/opt/chainsaw/hooks/ai-approved-packages.txt"

if ! grep -q "^${CHAINSAW_FORMAT}/${CHAINSAW_PACKAGE}$" "$APPROVED_LIST"; then
    echo "BLOCKED: AI agents may only install pre-approved packages"
    exit 1
fi

exit 0
This pattern is useful for restricting what AI coding assistants can install, ensuring they only use vetted packages.

Step 4: Make the Script Executable

chmod +x /opt/chainsaw/hooks/blocklist-check.sh

Step 5: Configure the Hook in Chainsaw

Navigate to Settings in the dashboard or configure via the settings API.

Via Dashboard

  1. Navigate to Settings
  2. Find the Hooks section
  3. Set the hook script path
  4. Save
Hook configuration in settings
Configure the hook script path in Chainsaw settings

Via API

curl -X PATCH "https://chain305.com/chainproxy/api/v1/settings" \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "hook_script": "/opt/chainsaw/hooks/blocklist-check.sh"
  }'

Step 6: Test the Hook

Install a package that should be blocked by your hook:

# If "malicious-package" is on your blocklist
npm install malicious-package \
  --registry https://CLIENT_ID:CLIENT_SECRET@chain305.com/chainproxy/repository/@default/npmjs/

Check the Traffic page to verify the hook blocked the request.

Traffic page showing hook-blocked request
Verify that hook-blocked requests appear in the Traffic view

Step 7: Monitor Hook Performance

Hooks run synchronously in the request path. Keep them fast to avoid latency:

  • Target < 100ms execution time
  • Use fail-open for external API calls (unless security requires fail-closed)
  • Cache results when possible
  • Monitor server logs for hook errors
A slow or hanging hook script will delay every package request. Set timeouts on any external API calls. If the hook exits non-zero unexpectedly, it surfaces as a 500 error for investigation.

Best Practices

  • Keep hooks simple — Complex logic belongs in a policy, not a hook
  • Use hooks for integrations — External blocklists, custom scanners, internal APIs
  • Log decisions — Echo a reason before exit 1 for debugging
  • Test thoroughly — A broken hook blocks all package installs
  • Version control hooks — Store hook scripts in a repo alongside your Chainsaw configuration
  • Set timeouts — Prevent hung external calls from blocking the pipeline

Next Steps