Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .jules/sentinel.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,8 @@
**Vulnerability:** Raw `stop()` and `warning()` calls without `call. = FALSE` in `llcont.R` and `vuongtest.R` exposed execution stack/call details when raised.
**Learning:** While some instances of `stop()` inside `tryCatch()` were previously fixed to hide the call stack, other standalone exceptions and warnings still leaked call context. Security must be consistently applied across the entire codebase.
**Prevention:** Always set `call. = FALSE` when using `stop()` or `warning()` to enforce a secure-by-default boundary and prevent internal execution paths from being disclosed to the end user.

## 2024-07-24 - Validate all arguments in exported functions
**Vulnerability:** Unvalidated arguments passed to exported functions like `vuongtest()` and `icci()` could trigger raw R errors deep inside internal logic (e.g., `if (adj == "aic")` failing with "missing value where TRUE/FALSE needed" when `adj=NA`), leaking internal execution contexts.
**Learning:** In R, evaluating unvalidated inputs (such as NA or vectors) inside control flow statements (`if`) throws raw errors that bypass top-level `stop(..., call. = FALSE)` safeguards, inadvertently exposing internal variables and call context.
**Prevention:** Always strictly validate the type, length, and bounds of user inputs at the very beginning of exported functions and fail securely using `stop("...", call. = FALSE)`.
4 changes: 4 additions & 0 deletions R/icci.R
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,10 @@
#' @export
icci <- function(object1, object2, conf.level=.95, ll1=llcont, ll2=llcont) {

if (!is.numeric(conf.level) || length(conf.level) != 1 || is.na(conf.level) || conf.level <= 0 || conf.level >= 1) {
stop("Argument 'conf.level' must be a single numeric value between 0 and 1.", call. = FALSE)
}

## check objects, issue warnings/errors, get classes/calls
obinfo <- check.obj(object1, object2)
callA <- obinfo$callA; classA <- obinfo$classA
Expand Down
7 changes: 7 additions & 0 deletions R/vuongtest.R
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,13 @@
#' @export
vuongtest <- function(object1, object2, nested=FALSE, adj="none", ll1=llcont, ll2=llcont, score1=NULL, score2=NULL, vc1=vcov, vc2=vcov) {

if (!is.logical(nested) || length(nested) != 1 || is.na(nested)) {
stop("Argument 'nested' must be a single logical value.", call. = FALSE)
}
if (!is.character(adj) || length(adj) != 1 || is.na(adj) || !(adj %in% c("none", "aic", "bic"))) {
stop("Argument 'adj' must be one of 'none', 'aic', or 'bic'.", call. = FALSE)
}
Comment thread
seonghobae marked this conversation as resolved.

## check objects, issue warnings/errors, get classes/calls
obinfo <- check.obj(object1, object2)
callA <- obinfo$callA; classA <- obinfo$classA
Expand Down
Loading