Files
jmiller 7c75133ef1
Universal: Auto Version Bump / Version Bump (push) Successful in 13s
Universal: PR Check / Branch Policy (pull_request) Successful in 1s
PR RC Release / Build RC Release (pull_request) Successful in 2s
Universal: PR Check / Validate PR (pull_request) Successful in 12s
Generic: Project CI / Lint & Validate (pull_request) Successful in 37s
Universal: PR Check / Secret Scan (pull_request) Successful in 1m20s
Generic: Project CI / Tests (pull_request) Has been cancelled
Universal: PR Check / Build RC Package (pull_request) Has been cancelled
Universal: PR Check / Report Issues (pull_request) Has been cancelled
feat: code security scanner with OWASP pattern detection (#552)
Implements the code analysis scanner module that detects insecure
patterns across Go, PHP, Python, JavaScript, and TypeScript:

- SQL injection (CWE-89): string concat in queries across 4 languages
- XSS (CWE-79): innerHTML, document.write, unescaped output, dangerouslySetInnerHTML
- Command injection (CWE-78): exec with variables, shell=True, os.system
- Path traversal (CWE-22): unsanitized path joins, file open with user input
- Insecure deserialization (CWE-502): unserialize(), yaml.load()
- Hardcoded credentials (CWE-798): password assignments in source
- Weak cryptography (CWE-327): MD5/SHA-1 usage

22 rules total, language-filtered by file extension. Wired into the
existing scanner orchestrator via the CodeScanner config toggle.
API updated to expose code_scanner in GET/PATCH security config.

Claude-Session: https://claude.ai/code/session_011AAFzotGMf3ayvXhEmStCd
2026-06-28 08:15:34 -05:00

100 lines
2.7 KiB
Go

// Copyright 2026 Moko Consulting <hello@mokoconsulting.tech>
// SPDX-License-Identifier: GPL-3.0-or-later
package security
import (
"context"
repo_model "code.mokoconsulting.tech/MokoConsulting/MokoGitea/models/repo"
security_model "code.mokoconsulting.tech/MokoConsulting/MokoGitea/models/security"
"code.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/git"
"code.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/log"
)
// ScanPushForSecrets checks a commit for secrets and returns findings.
// Used by the pre-receive hook to block pushes containing secrets.
func ScanPushForSecrets(ctx context.Context, repoID int64, commit *git.Commit) []Finding {
cfg, err := security_model.GetScannerConfig(ctx, repoID)
if err != nil {
log.Error("ScanPushForSecrets: GetScannerConfig: %v", err)
return nil
}
if !cfg.Enabled || !cfg.BlockOnPush || !cfg.SecretScanner {
return nil
}
scanner := NewSecretScanner()
findings, err := scanner.ScanCommit(commit)
if err != nil {
log.Error("ScanPushForSecrets: ScanCommit: %v", err)
return nil
}
return findings
}
// ScanOnPush runs enabled scanners against a commit pushed to the default branch.
// Called from services/repository/push.go on default branch pushes.
func ScanOnPush(ctx context.Context, repo *repo_model.Repository, commit *git.Commit) {
if commit == nil {
return
}
cfg, err := security_model.GetScannerConfig(ctx, repo.ID)
if err != nil {
log.Error("SecurityScan: GetScannerConfig for %s: %v", repo.FullName(), err)
return
}
if !cfg.Enabled {
return
}
var scanners []Scanner
if cfg.SecretScanner {
scanners = append(scanners, NewSecretScanner())
}
if cfg.DependScanner {
scanners = append(scanners, NewDependencyScanner())
}
if cfg.CodeScanner {
scanners = append(scanners, NewCodeScanner())
}
if len(scanners) == 0 {
return
}
totalFindings := 0
for _, s := range scanners {
findings, err := s.ScanTree(commit)
if err != nil {
log.Error("SecurityScan: %s scanner for %s: %v", s.Type(), repo.FullName(), err)
continue
}
for _, f := range findings {
alert := &security_model.SecurityAlert{
RepoID: repo.ID,
Scanner: f.Scanner,
Severity: f.Severity,
RuleID: f.RuleID,
Title: f.Title,
Description: f.Description,
FilePath: f.FilePath,
LineNumber: f.LineNumber,
CommitSHA: f.CommitSHA,
Fingerprint: f.Fingerprint,
Metadata: f.Metadata,
}
if err := security_model.CreateOrUpdateAlert(ctx, alert); err != nil {
log.Error("SecurityScan: CreateOrUpdateAlert: %v", err)
}
totalFindings++
}
}
if totalFindings > 0 {
log.Warn("SecurityScan: %d findings in %s", totalFindings, repo.FullName())
}
}