Summary
main() accesses os.Args[1] on line 30 of ussher.go before the length check on line 48. Invoking ussher with no arguments crashes with a Go runtime panic instead of producing the intended usage: ussher <username> message.
Reproduction
$ ./ussher
panic: runtime error: index out of range [1] with length 1
(The clean log.Fatal("usage: ussher <username>") further down at line 49 is unreachable for the no-args case.)
Why this matters specifically for ussher
This binary lives in the SSH authentication path. A panic — rather than a clean error — produces a Go stack trace on stderr, which is mildly informative for an operator running ./ussher by hand, but for any caller that processes ussher's output (sshd parsing stdout, a probe/health-check, an --version script that misorders args), the trace is unexpected and the exit code is 2 (Go runtime panic) rather than 1 (clean fatal). It's also the kind of crash a reachability scan would flag as "potentially exploitable" at a glance, even though it isn't.
The --version short-circuit ironically suffers the same issue — bare ./ussher can never print version info because the args check happens first and panics before the version branch can match.
Approach
Move the length check to the very top of main, before any os.Args[1] access:
func main() {
if len(os.Args) < 2 {
// Pre-init-log fatal: write to stderr (the default log destination).
log.Fatal("usage: ussher <username>")
}
if os.Args[1] == "--version" {
PrintVersion()
return
}
// ... existing security checks, initLog, etc.
}
This is also a natural seam for the parseArgs extraction proposed in #13 — the new function would do the length and --version handling and return either a trigger to print version, a typed error, or a username string.
Acceptance criteria
Files
/home/user/ussher/ussher.go
Summary
main()accessesos.Args[1]on line 30 ofussher.gobefore the length check on line 48. Invokingussherwith no arguments crashes with a Go runtime panic instead of producing the intendedusage: ussher <username>message.Reproduction
(The clean
log.Fatal("usage: ussher <username>")further down at line 49 is unreachable for the no-args case.)Why this matters specifically for
ussherThis binary lives in the SSH authentication path. A panic — rather than a clean error — produces a Go stack trace on stderr, which is mildly informative for an operator running
./ussherby hand, but for any caller that processes ussher's output (sshd parsing stdout, a probe/health-check, an--versionscript that misorders args), the trace is unexpected and the exit code is 2 (Go runtime panic) rather than 1 (clean fatal). It's also the kind of crash a reachability scan would flag as "potentially exploitable" at a glance, even though it isn't.The
--versionshort-circuit ironically suffers the same issue — bare./usshercan never print version info because the args check happens first and panics before the version branch can match.Approach
Move the length check to the very top of
main, before anyos.Args[1]access:This is also a natural seam for the
parseArgsextraction proposed in #13 — the new function would do the length and--versionhandling and return either a trigger to print version, a typed error, or a username string.Acceptance criteria
./ussher(no args) printsusage: ussher <username>to stderr and exits non-zero, no Go panic../ussher --versioncontinues to work../ussher root(or any valid user) continues to work.ussher_test.go(per 0% test coverage on Run, main, and the security startup gates #13) covers the no-args path.Files
/home/user/ussher/ussher.go