Security scan using Claude - #4
Merged
Merged
Conversation
- rotateWriter.Close() called itself recursively instead of w.fp.Close(), causing a stack overflow on any file logger shutdown - FileLogManager was constructed with a nil filetracker map, causing an immediate panic on the first RegisterConfig or Submit call - signalreplicator.listen() iterated signalChannels without holding a lock while remove() held a write lock, producing a concurrent map access panic; the blocking channel send also risked deadlocking signal delivery entirely - time.AfterFunc was called inside a loop body for every SIGTERM/SIGINT/SIGKILL received, leaking goroutines blocked on a full channel Add regression tests for each fix to prevent reintroduction.
Updating package versions to fix issues that dependabot found.
- running() returned p.exited (true when stopped) under a name implying the opposite; simplified to return !p.exited - rotate() left w.fp nil when os.Rename failed, breaking all subsequent writes; now logs the error and falls through to create a fresh file - Removed unreferenced global fileLogManager variable - LogManager.Submit() sent to a nil channel when the engine key was missing from the map, causing a goroutine leak; added an ok check - Fixed log.Fatalf call using string concatenation instead of a format argument (missing comma) - p.exited was written without a lock while running() reads it under RLock; wrapped the assignment in Lock/Unlock to eliminate the race - Renamed rotateWriter.panic() to logError() to reflect actual behaviour - Added explicit ok check for *exec.ExitError type assertion in RunSecretProcess to make safety obvious to readers - Added comments in console.Submit() explaining why write errors are intentionally dropped (reporting them would reuse the broken pipe)
… complexity paths. Updating readme files. Adding in a new llms.txt file so agents can easily read details for launch.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
PR Description
This PR handles all the issues found in the security scan from below.
Code Review Report - Launch Process Manager
Date: February 24, 2026
Project: Launch - Docker Container Process Manager
Reviewer: Automated Code Analysis
Executive Summary
This report documents a comprehensive security and code quality review of the Launch process manager codebase. Launch is designed to run as PID 1 in Docker containers, managing multiple processes with sophisticated logging capabilities.
Critical Finding: The codebase contains 6 CRITICAL bugs that will cause application crashes or failures. These must be addressed immediately before production use.
Severity Breakdown
Total Issues Found: 28
CRITICAL SEVERITY ISSUES
✅ Issue #1: Infinite Recursion in rotateWriter.Close()
File:
processlogger/filelogger/rotationwriter.go:114Severity: CRITICAL
Description:
The
Close()method calls itself recursively instead of closing the underlying file pointer.Impact:
Why Critical:
This makes graceful shutdown impossible. Every container using file logging will crash with a stack overflow when Launch tries to shutdown. This affects the core reliability promise of running as PID 1.
Fix Required:
✅ Issue #2: Nil Map Dereference in FileLogManager.Submit()
File:
processlogger/filelogger/filelogger.go:85Severity: CRITICAL
Description:
The
FileLogManagerstruct is initialized with&FileLogManager{}but thefiletrackermap is never initialized, remaining nil.Impact:
Why Critical:
File logging is advertised as a core feature but is completely non-functional. Any attempt to use it crashes the application.
Fix Required:
✅ Issue #3: Nil Map Access in FileLogManager.RegisterConfig()
File:
processlogger/filelogger/filelogger.go:37,41Severity: CRITICAL
Description:
Same root cause as Issue #2 - attempts to read and write to uninitialized map.
Impact:
Why Critical:
This prevents the application from even starting if file logging is configured. The failure happens during initialization phase.
Fix Required:
Same as Issue #2 - initialize the map in the constructor.
✅ Issue #4: Data Race in Signal Replicator
File:
signalreplicator/signal.go:68-71Severity: CRITICAL
Description:
The
listen()goroutine iterates over thesignalChannelsmap without holding a lock, whileregister()andremove()modify the same map under lock protection.Impact:
Why Critical:
This is a classic concurrency bug. Signal handling is core to process management in containers. The race condition will cause crashes at unpredictable times, especially during process startup/shutdown when signals are being registered/removed.
Fix Required:
✅ Issue #5: Goroutine Deadlock in Signal Replicator
File:
signalreplicator/signal.go:70Severity: CRITICAL
Description:
Sending signals to process channels is a blocking operation. If any process channel is full (buffer size 1) and the receiver isn't reading, the entire signal replication system deadlocks.
Impact:
Why Critical:
This is a PID 1 process manager. If signal delivery deadlocks, the entire container becomes unresponsive. Docker
stopcommands will hang, requiringkill -9.Fix Required:
✅ Issue #6: Multiple Timer Callbacks for Signal Handling
File:
processmanager/process.go:107-109Severity: CRITICAL
Description:
Each time a SIGTERM/SIGINT/SIGKILL arrives, a new
time.AfterFunccallback is created. If multiple signals arrive, multiple timers send to the same channel.Impact:
Why Critical:
Process lifecycle management is the core function of this tool. Multiple timeout callbacks break the state machine and can cause processes to be killed incorrectly or the application to misreport process state.
Fix Required:
HIGH SEVERITY ISSUES
✅ Issue #7: Wrong Variable Logged for STDERR
File:
processmanager/processmanager.go:268Severity: HIGH
Description:
The STDERR logging loop splits input by newlines but logs the entire unsplit data for each line, while STDOUT correctly logs individual lines.
Impact:
Why High:
While not crashing, this fundamentally breaks STDERR logging. Monitoring, alerting, and debugging all rely on accurate logs. This makes STDERR output unusable for troubleshooting.
Fix Required:
✅ Issue #8: Address-of Operator on Struct Fields in Nil Checks
File:
configfile/configfile.go:80,98,101,110Severity: HIGH
Description:
Multiple nil checks use the address-of operator
&on struct fields. The address of a field within an existing struct is never nil.Impact:
Why High:
This breaks the entire default configuration system. Processes without explicit logging config won't get defaults, leading to nil pointer dereferences elsewhere. The intention was clearly to check if the field is its zero value and apply defaults.
Fix Required:
These should likely check for zero values or use pointer fields:
✅ Issue #9: watchDog Goroutine Never Started
File:
processlogger/filelogger/rotationwriter.go:24-36Severity: HIGH
Description:
The
watchDogfunction exists to monitor file size and trigger rotations, but it's never called when arotateWriteris created.Impact:
size_limitandhistorical_files_limitare ignoredWhy High:
Log rotation is a documented feature with configuration options. Without it, any production deployment will eventually fill disk space and crash. This is particularly bad in container environments with limited disk.
Fix Required:
✅ Issue #10: Panic on Empty Byte Slice in BytePipe.Write()
File:
bytepipe/bytepipe.go:16Severity: HIGH
Description:
The
Writemethod checks if the last byte is a newline but doesn't validate that the slice is non-empty first.Impact:
p[-1]Why High:
While empty writes might be uncommon, they're valid according to the
io.Writerinterface contract. This violates the interface contract and makes the code fragile.Fix Required:
🔴 Issue #11: Unused shutdown Channel
File:
processmanager/process.go:25,151Severity: HIGH
Description:
The
Processstruct has ashutdownchannel that's created but never used anywhere in the codebase.Impact:
Why High:
This indicates incomplete implementation of what's likely a critical feature. Graceful shutdown is essential for a PID 1 process manager. The channel was clearly intended for something but was never fully implemented.
Recommendation:
Either implement the intended functionality or remove the dead code. If this was meant for external shutdown signaling, the feature should be completed.
✅ Issue #12: Uninitialized Error Return in BytePipe.Write()
File:
bytepipe/bytepipe.go:21Severity: HIGH
Description:
The
Writemethod uses named return parameters but never explicitly setserr, relying on implicit zero value.Impact:
io.Writerexpects errors to be explicitly returnedWhy High:
While it works (err is nil), this is a dangerous pattern. If someone adds error handling to one code path but forgets others, it will silently return an uninitialized error value. The code should be explicit about success.
Fix Required:
MEDIUM SEVERITY ISSUES
✅ Issue #13: Inverted Logic in Process.running() Method
File:
processmanager/process.go:31-39Severity: MEDIUM
Description:
The
running()method returnstruewhen the process has exited, which is semantically backwards.Impact:
Why Medium:
While confusing, the method is only called in one place (line 109) and the caller may be handling the inverted logic. However, this is a maintainability nightmare.
Fix Required:
✅ Issue #14: File Handle Leak in rotate() Error Path
File:
processlogger/filelogger/rotationwriter.go:131-139Severity: MEDIUM
Description:
If
os.Renamefails, the function returns early without creating a new file pointer, leavingw.fpin an inconsistent state.Impact:
Why Medium:
This is an error path that might not be commonly hit, but when it does, it breaks logging for that process permanently until restart.
Fix Required:
Restore the old file pointer or ensure a new one is always created, even after rename failures.
✅ Issue #15: Unused Global Variable
File:
processlogger/filelogger/filelogger.go:27Severity: MEDIUM
Description:
A global
fileLogManagervariable is declared but never used.Impact:
Why Medium:
Pure code quality issue. No functional impact but indicates incomplete refactoring or abandoned design approach.
Fix Required:
Remove the unused variable.
✅ Issue #16: Missing Nil Check on LogManager Map Access
File:
processlogger/logManager.go:145Severity: MEDIUM
Description:
The
Submitmethod accesses a map entry without checking if it exists.Impact:
Why Medium:
If configuration is properly validated, this shouldn't be hit. However, defensive programming would catch configuration errors more gracefully.
Fix Required:
✅ Issue #17: Log Format String Error
File:
main.go:222Severity: MEDIUM
Description:
String concatenation is used instead of format string parameters.
Impact:
Why Medium:
Functionally works but is poor practice and confusing to maintainers.
Fix Required:
✅ Issue #18: Race Condition in Process State Management
File:
processmanager/process.go:82-84,136Severity: MEDIUM
Description:
The
exitingflag is set under lock, butexitedis set without holding the lock.Impact:
running()methodWhy Medium:
While the race exists, the practical impact may be limited due to execution ordering. However, this violates concurrency best practices.
Fix Required:
LOW SEVERITY ISSUES
✅ Issue #19: Implicit Error Value Return
File:
bytepipe/bytepipe.go:21Severity: LOW
Description:
Same as Issue #12 but categorized as low if only considering functionality (works correctly but poor practice).
✅ Issue #20: Ignored Errors in Console Logger
File:
processlogger/console/console.go:56-62Severity: LOW
Description:
Errors from writing to stdout/stderr are silently ignored.
Impact:
Why Low:
Writing to stdout/stderr rarely fails, and there's limited recovery options if it does. However, the errors should at least be logged internally.
✅ Issue #21: Unchecked Type Assertion
File:
processmanager/process.go:179Severity: LOW
Description:
Type assertion without explicit ok check, though it's validated by prior function call.
Impact:
Why Low:
The code is actually safe due to readExitError's validation, but the safety is non-obvious.
✅ Issue #22: Misleading Function Name
File:
processlogger/filelogger/rotationwriter.go:68-72Severity: LOW
Description:
Function named
panic()doesn't actually panic.Impact:
Why Low:
Purely a naming issue, no functional impact.
Fix Required:
Rename to
handleError()orlogError().✅ Issue #23: Theoretical Integer Overflow
File:
processlogger/filelogger/rotationwriter.go:104Severity: LOW
Description:
File size counter could theoretically overflow uint64.
Impact:
Why Low:
Not a practical concern for container lifetimes.
SECURITY CONCERNS
🔐 Issue #24: Command Execution from Configuration
File:
processmanager/processmanager.go:219Severity: MEDIUM (Security Context)
Description:
Commands are executed directly from YAML configuration without validation.
Impact:
Why Medium:
This is the intended design of a process manager, but the security implications should be clearly documented. Configuration files should be protected.
Recommendation:
Add security documentation:
🔐 Issue #25: Unvalidated File Paths
File:
processlogger/filelogger/rotationwriter.go:142Severity: LOW (Security Context)
Description:
Log file paths from configuration are used without validation.
Impact:
../../../../etc/passwd)Why Low:
Container security and file permissions provide defense in depth. An attacker who can modify config likely has broader access anyway.
Recommendation:
Validate that log paths are within expected directories.
DOCUMENTATION ISSUES
📄 Issue #26: Broken Link in README.md
File:
README.md:44Severity: LOW (Documentation)
Description:
Reference to configuration documentation uses wrong filename case.
Actual file:
READMEs/ConfigrationFile.md(note: lowercase.md)Impact:
📄 Issue #27: Typo in Configuration Filename
File:
READMEs/ConfigrationFile.mdSeverity: LOW (Documentation)
Description:
Filename has typo: "Configration" should be "Configuration"
Impact:
Fix Required:
Rename file to
ConfigurationFile.md📄 Issue #28: Mismatched Quotes in README.md
File:
README.md:53Severity: LOW (Documentation)
Description:
Syntax error in code block example.
Impact:
Fix Required:
PRIORITIZED FIX RECOMMENDATIONS
IMMEDIATE (Production Blockers)
Must fix before any production use:
Close()Estimated Impact: These 6 critical bugs will cause application crashes. File logging is completely broken, shutdown is impossible, and signal handling has race conditions.
HIGH PRIORITY (Core Functionality)
Should fix before any significant use:
Estimated Impact: These issues break core functionality like logging, configuration defaults, and log rotation. The application may appear to work but will fail in production scenarios.
MEDIUM PRIORITY (Stability)
Fix when able:
Estimated Impact: Stability and maintainability improvements. Some may cause issues in edge cases.
LOW PRIORITY (Code Quality)
Technical debt:
18-23. Issues #19-#23 - Code quality improvements
24-25. Issues #24-#25 - Add security documentation
26-28. Issues #26-#28 - Fix documentation
TESTING RECOMMENDATIONS
Critical Tests Needed
File Logging Test
Signal Handling Test
Configuration Test
Integration Test
SUMMARY
This codebase has 6 CRITICAL bugs that must be fixed immediately:
The application cannot be used in production until these are resolved. Additionally, 6 HIGH severity issues should be addressed before any significant usage.
Overall Assessment: The codebase shows good architectural design and clear separation of concerns. However, critical implementation bugs in core subsystems (file logging, signal handling, configuration) prevent production readiness. The bugs are straightforward to fix once identified.