How to Catch Security Vulnerabilities Before They Reach Your Pull Requests
Author: Umair Mirza | Date: September 14, 2026 | Tag: #Security
!How to Catch Security Vulnerabilities in Code Before They Reach Your Pull Requests
Security reviews are most effective when developers receive feedback while the code is still fresh in their minds. Waiting until a pull request, CI build, or penetration test to find exposed credentials and insecure patterns creates unnecessary rework.
A lightweight way to shift security left is to run static application security testing (SAST) locally through Git pre-commit hooks.
In this guide, you'll install the DevSkim CLI, wire it into pre-commit so it lints staged files, add a dedicated secret scanner alongside it, verify the setup with a deliberate failure, and enforce the same checks in CI.
What We'll Cover:
- Why Pre-Commit Security Scanning?
- What Is DevSkim?
- Prerequisites
- Create a Pre-Commit Configuration
- Install the Git Hook
- Verify the Setup With a Deliberate Failure
- Example: Catching a Hardcoded Secret
- Keep Hooks Fast and Focused
- Handling False Positives
- Add Security Checks to CI Too
- Practical Rollout Tips
- Final Thoughts
Why Pre-Commit Security Scanning?
By 2026, supply chain attacks and credential leaks remain among the most common causes of breaches. The average cost of a data breach now exceeds $5 million, and organizations are under increasing pressure to demonstrate secure development practices.
Shifting security left is no longer a nice-to-have โ it's a regulatory and business imperative. Pre-commit hooks catch issues at the earliest possible stage, before code ever leaves a developer's machine. This approach offers several advantages:
- Immediate feedback while context is fresh
- Reduced rework by catching issues before code review
- Lower CI costs by preventing bad commits from triggering expensive pipelines
- Consistent enforcement across the entire team
What Is DevSkim?
DevSkim is an open-source, lightweight security linter from Microsoft. Unlike heavier SAST tools, DevSkim is designed for speed and developer experience โ it scans code in milliseconds and provides actionable, context-aware warnings for insecure patterns.
DevSkim supports dozens of languages including Python, JavaScript, TypeScript, Go, Java, C#, and more. It comes with a rich rule set covering common vulnerabilities like SQL injection, weak cryptography, insecure deserialization, and hardcoded secrets.
In 2026, DevSkim has become a popular choice for pre-commit workflows precisely because it balances coverage with speed โ a critical requirement when hooks run on every commit.
Prerequisites
Before you begin, ensure you have:
- Git installed and a repository to work with
- Python 3.9+ (for the
pre-commitframework) - pip or pipx for installing tools
- Docker (optional, for containerized scanning)
Create a Pre-Commit Configuration
The pre-commit framework makes it easy to manage and share Git hooks across a team. If you don't already have it installed:
pip install pre-commit
Next, create a .pre-commit-config.yaml file at the root of your repository:
repos:
- repo: https://github.com/microsoft/DevSkim
rev: v1.0.50
hooks:
- id: devskim
name: DevSkim Security Linter
entry: devskim analyze
language: system
types: [text]
pass_filenames: true
args: ["--file-format", "sarif", "--output", "devskim-results.sarif"]
- repo: https://github.com/gitleaks/gitleaks
rev: v8.21.0
hooks:
- id: gitleaks
name: Gitleaks Secret Scanner
This configuration does two things:
- DevSkim scans staged files for insecure patterns
- Gitleaks scans for hardcoded secrets, API keys, and credentials
- Limit scope โ scan only staged files, not the entire repo
- Use lightweight tools โ DevSkim and Gitleaks are optimized for speed
- Avoid duplicate scans โ don't run the same check in pre-commit and pre-push
- Parallelize โ
pre-commitruns hooks concurrently by default - Pilot with a small team โ get feedback before mandating across the org
- Pre-stage the config โ add
.pre-commit-config.yamland.gitleaks.tomlto the repo template - Communicate clearly โ explain why the hooks exist and how to respond to alerts
- Measure impact โ track how many issues are caught pre-commit vs. in CI or production
- Review rules quarterly โ the threat landscape changes; keep rules current
Install the Git Hook
Run the following command in your repository root:
pre-commit install
This installs the hook into .git/hooks/pre-commit. From now on, every git commit will trigger the configured scanners.
You can also run the hooks manually against all files:
pre-commit run --all-files
Verify the Setup With a Deliberate Failure
To confirm the hook works, create a file with a known insecure pattern:
# insecure_test.py
import hashlib
password = "admin123" # hardcoded credential
hashed = hashlib.md5(password.encode()).hexdigest()
Now stage and commit the file:
git add insecure_test.py
git commit -m "test security hook"
DevSkim should flag the weak MD5 usage, and Gitleaks should flag the hardcoded password. The commit will be blocked โ that's exactly what you want.
Example: Catching a Hardcoded Secret
Here's the kind of output Gitleaks produces when it catches an AWS key:
Finding: AWS Access Key
Secret: AKIAIOSFODNN7EXAMPLE
RuleID: aws-access-token
Entropy: 3.65
File: config.py
Line: 14
Because the hook runs locally, the secret never reaches the remote repository. This is critical โ once a secret is pushed, it must be considered compromised and rotated immediately.
Keep Hooks Fast and Focused
Pre-commit hooks should run in under a few seconds. If they slow down commits, developers will bypass them with --no-verify. To keep things fast:
Handling False Positives
No scanner is perfect. When DevSkim or Gitleaks flags a false positive, use inline suppression comments:
# devskim:ignore DS126858
hashlib.md5(password.encode())
For Gitleaks, use a .gitleaks.toml config file to define allowlists:
[allowlist]
description = "Ignore test fixtures"
paths = ["tests/fixtures/.*"]
Document every suppression with a comment explaining why it's safe. Undocumented suppressions tend to multiply and erode security posture over time.
Add Security Checks to CI Too
Pre-commit hooks are a first line of defense, but they can be bypassed. Enforce the same checks in CI to guarantee coverage:
# .github/workflows/security.yml
name: Security Scan
on: [push, pull_request]
jobs:
scan:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: '3.12'
- run: pip install pre-commit
- run: pre-commit run --all-files
This ensures that even if a developer skips the local hook, the CI will catch the issue before merge. By 2026, most CI platforms also offer native secret scanning (GitHub Advanced Security, GitLab Secret Detection), which can complement the setup.
Practical Rollout Tips
Final Thoughts
Catching security vulnerabilities before they reach a pull request is one of the highest-leverage investments a development team can make. Pre-commit hooks powered by DevSkim and Gitleaks deliver fast, actionable feedback at the exact moment developers can act on it.
Combined with CI enforcement and periodic rule reviews, this lightweight shift-left approach meaningfully reduces the risk of shipping insecure code โ without slowing down delivery.
Have you integrated security scanning into your pre-commit workflow? Share your experience in the comments.
via FreeCodeCamp
