security: validate revision parameter to prevent Nix injection
The revision parameter was interpolated directly into a Nix expression, allowing potential injection of arbitrary Nix code. An attacker could craft a revision string like: "; builtins.readFile /etc/passwd; " This adds ValidateRevision() which ensures revisions only contain safe characters (alphanumeric, hyphens, underscores, dots) and are at most 64 characters long. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -11,12 +11,18 @@ import (
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"git.t-juice.club/torjus/labmcp/internal/database"
|
||||
)
|
||||
|
||||
// revisionPattern validates revision strings to prevent injection attacks.
|
||||
// Allows: alphanumeric, hyphens, underscores, dots (for channel names like "nixos-24.11"
|
||||
// and git hashes). Must be 1-64 characters.
|
||||
var revisionPattern = regexp.MustCompile(`^[a-zA-Z0-9._-]{1,64}$`)
|
||||
|
||||
// Indexer handles indexing of nixpkgs revisions.
|
||||
type Indexer struct {
|
||||
store database.Store
|
||||
@@ -42,10 +48,24 @@ type IndexResult struct {
|
||||
AlreadyIndexed bool // True if revision was already indexed (skipped)
|
||||
}
|
||||
|
||||
// ValidateRevision checks if a revision string is safe to use.
|
||||
// Returns an error if the revision contains potentially dangerous characters.
|
||||
func ValidateRevision(revision string) error {
|
||||
if !revisionPattern.MatchString(revision) {
|
||||
return fmt.Errorf("invalid revision format: must be 1-64 alphanumeric characters, hyphens, underscores, or dots")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// IndexRevision indexes a nixpkgs revision by git hash or channel name.
|
||||
func (idx *Indexer) IndexRevision(ctx context.Context, revision string) (*IndexResult, error) {
|
||||
start := time.Now()
|
||||
|
||||
// Validate revision to prevent injection attacks
|
||||
if err := ValidateRevision(revision); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Resolve channel names to git refs
|
||||
ref := resolveRevision(revision)
|
||||
|
||||
@@ -116,6 +136,11 @@ func (idx *Indexer) IndexRevision(ctx context.Context, revision string) (*IndexR
|
||||
|
||||
// ReindexRevision forces re-indexing of a revision, deleting existing data first.
|
||||
func (idx *Indexer) ReindexRevision(ctx context.Context, revision string) (*IndexResult, error) {
|
||||
// Validate revision to prevent injection attacks
|
||||
if err := ValidateRevision(revision); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ref := resolveRevision(revision)
|
||||
|
||||
// Delete existing revision if present
|
||||
|
||||
Reference in New Issue
Block a user