Security scanning tools exist on a spectrum from "runs on your laptop in 10 seconds" to "requires a six-month enterprise procurement process." Most teams oscillate between the two extremes, skipping the productive middle ground. That middle ground — automated, opinionated, integrated into CI — is where the real security posture improvement happens.

This article covers the patterns we use to scan at the GitHub-organisation level: not just one repository, but all of them, on a schedule, with structured output that feeds into a remediation workflow.

The OWASP Top 10 as a scan ruleset

The OWASP Top 10 is not a checklist — it's a risk taxonomy. Each category maps to a set of detectable code and configuration patterns. Not all of them are automatable, but the most common ones are:

OWASP Category What we scan for
A01: Broken Access Control S3 buckets with public ACLs, missing IAM conditions, no resource policies
A02: Cryptographic Failures Hardcoded secrets, HTTP (not HTTPS) endpoints, weak cipher configs
A03: Injection String concatenation in SQL queries, shell=True in subprocess calls
A05: Security Misconfiguration Debug mode enabled, default credentials, missing security headers
A06: Vulnerable Components Dependencies with known CVEs, outdated major versions
A09: Logging Failures Missing audit logging, print() in production, no structured log format

Scanning at org scale with the GitHub API

The GitHub API's /orgs/{org}/repos endpoint returns all repositories in an organisation (paginated). With an authenticated PAT (5,000 requests/hour), you can enumerate all repos, fetch their file trees, and download specific files for analysis — all within the free tier of the GitHub API.

# Enumerate all repos in an org and scan each
import asyncio
from github_client import GitHubClient
from scanner import scan_repository

async def scan_org(org: str, pat: str) -> list[dict]:
    client = GitHubClient(pat)
    repos = client.list_org_repos(org)  # handles pagination

    # Scan up to 10 repos concurrently
    semaphore = asyncio.Semaphore(10)

    async def scan_one(repo):
        async with semaphore:
            return await scan_repository(
                repo_url=f"https://github.com/{org}/{repo['name']}",
                scan_id=generate_scan_id(),
            )

    return await asyncio.gather(*[scan_one(r) for r in repos])

Secret detection: the highest-value scan

Hardcoded credentials are the single highest-return security scan. Automated scanners harvest leaked credentials from GitHub within minutes of a commit — there are bots running continuously watching for AWS key patterns, GitHub tokens, Stripe keys, and more.

The patterns to scan for:

When you find a hardcoded credential: Treat it as already compromised. Rotate it immediately — before patching the code. Assume the credential was harvested within the first hour of the commit being public. The patch is secondary to the rotation.

IaC security scanning

Infrastructure as Code files (Terraform, CloudFormation, Pulumi) are often more security-critical than application code, but receive less scrutiny. Common patterns:

Public S3 buckets

Any Terraform resource with acl = "public-read" or block_public_acls = false without explicit data classification sign-off. Default should be private. Public delivery should use CloudFront OAC, not open ACLs.

Unbounded Lambda concurrency

A Lambda with no reserved_concurrent_executions set can exhaust your account's total concurrency (default: 1000). On Free Tier, unexpected traffic can consume your monthly compute allocation before you notice.

Missing encryption

DynamoDB tables, S3 buckets, and SQS queues without server-side encryption enabled. SSE-S3 (AES-256) is free and should be the default for all storage resources.

Integrating into CI/CD

The most effective position for security scanning is as a PR check — before merge, not after. The workflow:

  1. PR opened → scanner runs on changed files only (fast, targeted)
  2. Critical/High findings → PR check fails, merge blocked
  3. Medium/Low findings → PR check warns, merge allowed (with annotation)
  4. Weekly full-repo scan → catches findings in unchanged files

This separation — fast targeted scan on PR, full scan on schedule — keeps CI times under 60 seconds while still catching the full range of findings over time.

What the ticketyboo scanner checks

The scanner checks every repository against five categories. Security findings include hardcoded credentials, public S3 configuration, and missing security policies. Each finding includes a severity rating, the affected file, and a concrete remediation recommendation.

Try it on your repository →

Related tools and articles

→ Scan your repository for security findings → Governance as code → Data governance and GDPR compliance → AI-assisted remediation