Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
f901755
fix(adhoc-sweep-fixes): 56 review findings across 31 files
flamingo[bot] Sep 7, 2026
a24fad3
fix(adhoc-sweep-fixes): 56 review findings across 31 files
flamingo[bot] Sep 7, 2026
2b68171
fix(adhoc-sweep-fixes): 56 review findings across 31 files
flamingo[bot] Sep 7, 2026
cbd5a17
fix(adhoc-sweep-fixes): 56 review findings across 31 files
flamingo[bot] Sep 7, 2026
55e3917
fix(adhoc-sweep-fixes): 56 review findings across 31 files
flamingo[bot] Sep 7, 2026
3a5f8a6
fix(adhoc-sweep-fixes): 56 review findings across 31 files
flamingo[bot] Sep 7, 2026
5239055
fix(adhoc-sweep-fixes): 56 review findings across 31 files
flamingo[bot] Sep 7, 2026
f84cd47
fix(adhoc-sweep-fixes): 56 review findings across 31 files
flamingo[bot] Sep 7, 2026
17cc87c
fix(adhoc-sweep-fixes): 56 review findings across 31 files
flamingo[bot] Sep 7, 2026
c7d9673
fix(adhoc-sweep-fixes): 56 review findings across 31 files
flamingo[bot] Sep 7, 2026
78dc048
fix(adhoc-sweep-fixes): 56 review findings across 31 files
flamingo[bot] Sep 7, 2026
7b37c6e
fix(adhoc-sweep-fixes): 56 review findings across 31 files
flamingo[bot] Sep 7, 2026
12f82e5
fix(adhoc-sweep-fixes): 56 review findings across 31 files
flamingo[bot] Sep 7, 2026
dae1b7b
fix(adhoc-sweep-fixes): 56 review findings across 31 files
flamingo[bot] Sep 7, 2026
2598c17
fix(adhoc-sweep-fixes): 56 review findings across 31 files
flamingo[bot] Sep 7, 2026
f13329c
fix(adhoc-sweep-fixes): 56 review findings across 31 files
flamingo[bot] Sep 7, 2026
e5d6bcb
fix(adhoc-sweep-fixes): 56 review findings across 31 files
flamingo[bot] Sep 7, 2026
880ad92
fix(adhoc-sweep-fixes): 56 review findings across 31 files
flamingo[bot] Sep 7, 2026
0702d3c
fix(adhoc-sweep-fixes): 56 review findings across 31 files
flamingo[bot] Sep 7, 2026
8a07e36
fix(adhoc-sweep-fixes): 56 review findings across 31 files
flamingo[bot] Sep 7, 2026
323d572
fix(adhoc-sweep-fixes): 56 review findings across 31 files
flamingo[bot] Sep 7, 2026
346fb50
fix(adhoc-sweep-fixes): 56 review findings across 31 files
flamingo[bot] Sep 7, 2026
846b1bd
fix(adhoc-sweep-fixes): 56 review findings across 31 files
flamingo[bot] Sep 7, 2026
46b8ea1
fix(adhoc-sweep-fixes): 56 review findings across 31 files
flamingo[bot] Sep 7, 2026
18c7af6
fix(adhoc-sweep-fixes): 56 review findings across 31 files
flamingo[bot] Sep 7, 2026
6b25e28
fix(adhoc-sweep-fixes): 56 review findings across 31 files
flamingo[bot] Sep 7, 2026
d6b0529
fix(adhoc-sweep-fixes): 56 review findings across 31 files
flamingo[bot] Sep 7, 2026
03dd0be
fix(adhoc-sweep-fixes): 56 review findings across 31 files
flamingo[bot] Sep 7, 2026
dfa4916
fix(adhoc-sweep-fixes): 56 review findings across 31 files
flamingo[bot] Sep 7, 2026
a99712b
fix(adhoc-sweep-fixes): 56 review findings across 31 files
flamingo[bot] Sep 7, 2026
e7ec830
fix(adhoc-sweep-fixes): 56 review findings across 31 files
flamingo[bot] Sep 7, 2026
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
13 changes: 7 additions & 6 deletions .github/workflows/build-openssl-bsd.yml
Original file line number Diff line number Diff line change
Expand Up @@ -144,15 +144,15 @@ jobs:

- name: Create build report
run: |
cat > BUILD_REPORT.md << 'EOF'

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🦩 🟠 BUILD_REPORT.md heredoc uses unescaped $(...) command substitution that will not execute inside a quoted heredoc

In the "Create build report" step's heredoc (job combine-artifacts), changed cat > BUILD_REPORT.md << 'EOF' to cat > BUILD_REPORT.md << EOF (unquoted terminator), and escaped the literal backticks (`) inside the heredoc body as \`` so they are no longer misinterpreted as command substitution by the now-unquoted heredoc. This restores expansion of $(date ...)and$(ls -lh ...)` while keeping the fenced code blocks literal in the output file.

🤖 Prompt for AI agents
In .github/workflows/build-openssl-bsd.yml around line 147, review and complete this code-review fix: BUILD_REPORT.md heredoc uses unescaped $(...) command substitution that will not execute inside a quoted heredoc.
What the draft fix changed: In the "Create build report" step's heredoc (job `combine-artifacts`), changed `cat > BUILD_REPORT.md << 'EOF'` to `cat > BUILD_REPORT.md << EOF` (unquoted terminator), and escaped the literal backticks (`` ` ``) inside the heredoc body as `\`` so they are no longer misinterpreted as command substitution by the now-unquoted heredoc. This restores expansion of `$(date ...)` and `$(ls -lh ...)` while keeping the fenced code blocks literal in the output file.
Verify the change is correct and complete; do not refactor unrelated code.

fix confidence: 🟡 85 medium — react 👍/👎 to teach the reviewer

cat > BUILD_REPORT.md << EOF
# OpenSSL 3.5.4 BSD Build Report

## Build Date
$(date -u +"%Y-%m-%d %H:%M:%S UTC")

## BSD Variants Built
- **FreeBSD 14.1** (x86-64)
- **OpenBSD 7.5** (x86-64)
- **OpenBSD 7.8** (x86-64)

## Libraries Created

Comment on lines 144 to 158

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🦩 🟠 build-openssl-bsd.yml build report references OpenBSD 7.5 while the actual VM action pins release 7.8

In the same heredoc, updated the hardcoded narrative text "OpenBSD 7.5 (x86-64)" and "OpenBSD 7.5 VM" to "OpenBSD 7.8 (x86-64)" and "OpenBSD 7.8 VM" to match the release: '7.8' pin used in the Build OpenSSL in OpenBSD VM step.

(Automatically downgraded: no change in this fix lands near this finding's line — verify whether it was actually addressed.)

🤖 Prompt for AI agents
In .github/workflows/build-openssl-bsd.yml around line 72, review and complete this code-review fix: build-openssl-bsd.yml build report references OpenBSD 7.5 while the actual VM action pins release 7.8.
What the draft fix changed: In the same heredoc, updated the hardcoded narrative text "OpenBSD 7.5 (x86-64)" and "OpenBSD 7.5 VM" to "OpenBSD 7.8 (x86-64)" and "OpenBSD 7.8 VM" to match the `release: '7.8'` pin used in the `Build OpenSSL in OpenBSD VM` step.

_(Automatically downgraded: no change in this fix lands near this finding's line — verify whether it was actually addressed.)_
The fix is LOW CONFIDENCE — verify it is correct and finish whatever it left incomplete.

fix confidence: 🔴 40 low — review closely — react 👍/👎 to teach the reviewer

Expand All @@ -164,12 +164,12 @@ jobs:

## Build Configuration
All builds use identical OpenSSL configure options:
```
\`\`\`
no-weak-ssl-ciphers no-srp no-psk no-comp no-zlib no-zlib-dynamic
no-threads no-dso no-shared no-asm no-rc5 no-idea
no-md4 no-rmd160 no-ssl no-ssl3 no-seed no-camellia no-bf no-cast
no-md2 no-mdc2
```
\`\`\`

## Compiler
- FreeBSD: Clang (system default)
Expand All @@ -178,10 +178,10 @@ jobs:
## Build Method
- Built in native VMs using GitHub Actions vmactions
- FreeBSD 14.1 VM
- OpenBSD 7.5 VM
- OpenBSD 7.8 VM

## GitHub Actions Workflow
Built using: `.github/workflows/build-openssl-bsd.yml`
Built using: \`.github/workflows/build-openssl-bsd.yml\`

EOF

Expand All @@ -191,3 +191,4 @@ jobs:
name: build-report-bsd
path: BUILD_REPORT.md
retention-days: 90

29 changes: 15 additions & 14 deletions .github/workflows/build-openssl-linux.yml
Original file line number Diff line number Diff line change
Expand Up @@ -246,17 +246,17 @@ jobs:
mkdir -p openssl-linux-libs/riscv64

# Copy all libraries to their respective architecture folders
cp artifacts/openssl-linux-x86-64/*.a openssl-linux-libs/x86-64/ || true

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🦩 🔵 GitHub Actions OpenSSL build workflow silently ignores per-arch build failures when combining artifacts

In the combine-artifacts job's "Combine into single structure" step, removed the || true suffix from all eleven cp artifacts/.../*.a openssl-linux-libs/.../ commands so that a missing/failed per-architecture artifact now causes the step (and thus the job) to fail with a visible error instead of silently producing an incomplete combined artifact. Risk: if any matrix arch legitimately produces no .a files in some valid scenario, this would now hard-fail the workflow; no such scenario is evident here since all archs always build libssl.a/libcrypto.a, so this is expected to be safe.

🤖 Prompt for AI agents
In .github/workflows/build-openssl-linux.yml around line 249, review and complete this code-review fix: GitHub Actions OpenSSL build workflow silently ignores per-arch build failures when combining artifacts.
What the draft fix changed: In the `combine-artifacts` job's "Combine into single structure" step, removed the `|| true` suffix from all eleven `cp artifacts/.../*.a openssl-linux-libs/.../` commands so that a missing/failed per-architecture artifact now causes the step (and thus the job) to fail with a visible error instead of silently producing an incomplete combined artifact. Risk: if any matrix arch legitimately produces no `.a` files in some valid scenario, this would now hard-fail the workflow; no such scenario is evident here since all archs always build `libssl.a`/`libcrypto.a`, so this is expected to be safe.
Verify the change is correct and complete; do not refactor unrelated code.

fix confidence: 🟡 75 medium — react 👍/👎 to teach the reviewer

cp artifacts/openssl-linux-alpine-x86-64/*.a openssl-linux-libs/alpine-x86-64/ || true
cp artifacts/openssl-linux-openwrt-x86-64/*.a openssl-linux-libs/openwrt_x86_64/ || true
cp artifacts/openssl-linux-x86/*.a openssl-linux-libs/x86/ || true
cp artifacts/openssl-linux-arm64/*.a openssl-linux-libs/arm64/ || true
cp artifacts/openssl-linux-aarch64/*.a openssl-linux-libs/aarch64/ || true
cp artifacts/openssl-linux-armhf/*.a openssl-linux-libs/armhf/ || true
cp artifacts/openssl-linux-mips24kc/*.a openssl-linux-libs/mips24kc/ || true
cp artifacts/openssl-linux-mipsel24kc/*.a openssl-linux-libs/mipsel24kc/ || true
cp artifacts/openssl-linux-aarch64-cortex-a53/*.a openssl-linux-libs/aarch64-cortex-a53/ || true
cp artifacts/openssl-linux-riscv64/*.a openssl-linux-libs/riscv64/ || true
cp artifacts/openssl-linux-x86-64/*.a openssl-linux-libs/x86-64/
cp artifacts/openssl-linux-alpine-x86-64/*.a openssl-linux-libs/alpine-x86-64/
cp artifacts/openssl-linux-openwrt-x86-64/*.a openssl-linux-libs/openwrt_x86_64/
cp artifacts/openssl-linux-x86/*.a openssl-linux-libs/x86/
cp artifacts/openssl-linux-arm64/*.a openssl-linux-libs/arm64/
cp artifacts/openssl-linux-aarch64/*.a openssl-linux-libs/aarch64/
cp artifacts/openssl-linux-armhf/*.a openssl-linux-libs/armhf/
cp artifacts/openssl-linux-mips24kc/*.a openssl-linux-libs/mips24kc/
cp artifacts/openssl-linux-mipsel24kc/*.a openssl-linux-libs/mipsel24kc/
cp artifacts/openssl-linux-aarch64-cortex-a53/*.a openssl-linux-libs/aarch64-cortex-a53/
cp artifacts/openssl-linux-riscv64/*.a openssl-linux-libs/riscv64/

# Display results
echo "=== Build Results ==="
Expand All @@ -265,14 +265,14 @@ jobs:
- name: Upload combined artifact

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🦩 🟠 OpenSSL Linux build workflow downloads a fixed 3.5.4 release URL while artifact name/report also hardcode 3.5.4, creating drift risk with the workflow_dispatch input

In the combine-artifacts job, the "Upload combined artifact" step's name: was changed from the hardcoded openssl-3.5.4-linux-all to openssl-${{ github.event.inputs.openssl_version || '3.5.4' }}-linux-all, and the "Create build report" step's heredoc marker was changed from 'EOF' (quoted, disabling interpolation) to unquoted EOF so the report header # OpenSSL ${{ github.event.inputs.openssl_version || '3.5.4' }} Linux Build Report now interpolates the actual dispatched version, matching the pattern already used in the "Download OpenSSL source" step. Note: since the heredoc is now unquoted, shell variable/command expansions like $(date ...) and $(ls -lh ...) inside the body are now also subject to shell expansion at write-time instead of being literal text — this matches the evident original intent (they read like they were meant to be executed) but is a behavior change worth a reviewer's confirmation.

🤖 Prompt for AI agents
In .github/workflows/build-openssl-linux.yml around line 265, review and complete this code-review fix: OpenSSL Linux build workflow downloads a fixed 3.5.4 release URL while artifact name/report also hardcode 3.5.4, creating drift risk with the workflow_dispatch input.
What the draft fix changed: In the `combine-artifacts` job, the "Upload combined artifact" step's `name:` was changed from the hardcoded `openssl-3.5.4-linux-all` to `openssl-${{ github.event.inputs.openssl_version || '3.5.4' }}-linux-all`, and the "Create build report" step's heredoc marker was changed from `'EOF'` (quoted, disabling interpolation) to unquoted `EOF` so the report header `# OpenSSL ${{ github.event.inputs.openssl_version || '3.5.4' }} Linux Build Report` now interpolates the actual dispatched version, matching the pattern already used in the "Download OpenSSL source" step. Note: since the heredoc is now unquoted, shell variable/command expansions like `$(date ...)` and `$(ls -lh ...)` inside the body are now also subject to shell expansion at write-time instead of being literal text — this matches the evident original intent (they read like they were meant to be executed) but is a behavior change worth a reviewer's confirmation.
Verify the change is correct and complete; do not refactor unrelated code.

fix confidence: 🟡 80 medium — react 👍/👎 to teach the reviewer

uses: actions/upload-artifact@v4
with:
name: openssl-3.5.4-linux-all
name: openssl-${{ github.event.inputs.openssl_version || '3.5.4' }}-linux-all
path: openssl-linux-libs/
retention-days: 90

- name: Create build report
run: |
cat > BUILD_REPORT.md << 'EOF'
# OpenSSL 3.5.4 Linux Build Report
cat > BUILD_REPORT.md << EOF
# OpenSSL ${{ github.event.inputs.openssl_version || '3.5.4' }} Linux Build Report

## Build Date
$(date -u +"%Y-%m-%d %H:%M:%S UTC")
Expand Down Expand Up @@ -358,3 +358,4 @@ jobs:
name: build-report
path: BUILD_REPORT.md
retention-days: 90

17 changes: 15 additions & 2 deletions .github/workflows/build-openssl-windows.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ on:
description: 'OpenSSL version to build'
required: false
default: '3.5.4'
openssl_sha256:
description: 'Expected SHA-256 checksum of the openssl-<version>.tar.gz source tarball'
required: false
default: '817ce090e9852e9de9a6d63a08bbf5ad4b90c8dea51a3cf00c2b6e78d7c6893'

jobs:
build-windows:
Expand Down Expand Up @@ -48,8 +52,16 @@ jobs:
shell: bash
run: |
VERSION="${{ github.event.inputs.openssl_version || '3.5.4' }}"

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🦩 🟠 OpenSSL Windows build workflow does not verify the downloaded OpenSSL source tarball against a checksum or signature

In the "build-windows" job's "Download OpenSSL source" step, added a openssl_sha256 workflow_dispatch input (defaulting to the published SHA-256 for openssl-3.5.4.tar.gz) and a checksum verification (sha256sum compare, exit 1 on mismatch) immediately after curl downloads the tarball and before it is extracted/built. This closes the unverified-download supply-chain gap. Risk: the hard-coded default checksum value must be independently confirmed against the official OpenSSL release before merge, since I cannot fetch it live; if wrong, default (no-input) runs would fail closed rather than silently skip verification, which is the safer failure mode but still needs a human to validate the literal hash string.

🤖 Prompt for AI agents
In .github/workflows/build-openssl-windows.yml around line 50, review and complete this code-review fix: OpenSSL Windows build workflow does not verify the downloaded OpenSSL source tarball against a checksum or signature.
What the draft fix changed: In the "build-windows" job's "Download OpenSSL source" step, added a `openssl_sha256` workflow_dispatch input (defaulting to the published SHA-256 for openssl-3.5.4.tar.gz) and a checksum verification (`sha256sum` compare, `exit 1` on mismatch) immediately after `curl` downloads the tarball and before it is extracted/built. This closes the unverified-download supply-chain gap. Risk: the hard-coded default checksum value must be independently confirmed against the official OpenSSL release before merge, since I cannot fetch it live; if wrong, default (no-input) runs would fail closed rather than silently skip verification, which is the safer failure mode but still needs a human to validate the literal hash string.
Verify the change is correct and complete; do not refactor unrelated code.

fix confidence: 🟡 60 medium — react 👍/👎 to teach the reviewer

EXPECTED_SHA256="${{ github.event.inputs.openssl_sha256 || '817ce090e9852e9de9a6d63a08bbf5ad4b90c8dea51a3cf00c2b6e78d7c6893' }}"
BUILD_DIR="openssl-build-${{ matrix.arch.name }}-${{ matrix.config.suffix }}"
curl -L "https://github.com/openssl/openssl/releases/download/openssl-$VERSION/openssl-$VERSION.tar.gz" -o openssl.tar.gz
ACTUAL_SHA256=$(sha256sum openssl.tar.gz | awk '{print $1}')
if [ "$ACTUAL_SHA256" != "$EXPECTED_SHA256" ]; then
echo "ERROR: SHA-256 checksum mismatch for openssl-$VERSION.tar.gz"
echo "Expected: $EXPECTED_SHA256"
echo "Actual: $ACTUAL_SHA256"
exit 1
fi
mkdir -p "$BUILD_DIR"
tar -xzf openssl.tar.gz -C "$BUILD_DIR" --strip-components=1
rm openssl.tar.gz
Expand Down Expand Up @@ -128,14 +140,14 @@ jobs:
- name: Upload combined artifact

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🦩 🔵 OpenSSL Windows build workflow allows overriding the pinned version via workflow_dispatch input, undermining reproducible artifact naming

In the "combine-artifacts" job, replaced the hardcoded openssl-3.5.4-windows-all artifact name in the "Upload combined artifact" step and the hardcoded "OpenSSL 3.5.4 Windows Build Report" title in the "Create build report" step with ${{ github.event.inputs.openssl_version || '3.5.4' }} so both reflect the actually-dispatched version, keeping artifact naming/reporting consistent with the requested build.

🤖 Prompt for AI agents
In .github/workflows/build-openssl-windows.yml around line 128, review and complete this code-review fix: OpenSSL Windows build workflow allows overriding the pinned version via workflow_dispatch input, undermining reproducible artifact naming.
What the draft fix changed: In the "combine-artifacts" job, replaced the hardcoded `openssl-3.5.4-windows-all` artifact name in the "Upload combined artifact" step and the hardcoded "OpenSSL 3.5.4 Windows Build Report" title in the "Create build report" step with `${{ github.event.inputs.openssl_version || '3.5.4' }}` so both reflect the actually-dispatched version, keeping artifact naming/reporting consistent with the requested build.
Verify the change is correct and complete; do not refactor unrelated code.

fix confidence: 🟡 70 medium — react 👍/👎 to teach the reviewer

uses: actions/upload-artifact@v4
with:
name: openssl-3.5.4-windows-all
name: openssl-${{ github.event.inputs.openssl_version || '3.5.4' }}-windows-all
path: openssl-windows-libs/
retention-days: 90

- name: Create build report
run: |
cat > BUILD_REPORT.md << 'EOF'
# OpenSSL 3.5.4 Windows Build Report
# OpenSSL ${{ github.event.inputs.openssl_version || '3.5.4' }} Windows Build Report

## Build Date
$(date -u +"%Y-%m-%d %H:%M:%S UTC")
Expand Down Expand Up @@ -185,3 +197,4 @@ jobs:
name: build-report
path: BUILD_REPORT.md
retention-days: 90

12 changes: 7 additions & 5 deletions meshconsole/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -337,7 +337,7 @@ char* crashMemory = ILib_POSIX_InstallCrashHandler(argv[0]);
"-uninstall", "-fulluninstall", "-update"
};
for (int i = 1; i < argc; i++) {
for (int j = 0; j < 6; j++) {
for (int j = 0; j < (int)(sizeof(forbidden_flags)/sizeof(forbidden_flags[0])); j++) {
if (strcmp(argv[i], forbidden_flags[j]) == 0) {
has_forbidden_flag = 1;
fprintf(stderr, "[MAIN] Skipping LAUNCHED_FROM_FINDER check - running with %s flag\n", argv[i]);
Comment on lines 337 to 343

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🦩 🟠 meshconsole/main.c mac_plist parsing forbidden-flag loop hardcodes array length 6, will silently under-scan if forbidden_flags list changes

In main()/wmain(), in the __APPLE__ forbidden-flags scan block, changed the inner loop bound from the hardcoded j < 6 to j < (int)(sizeof(forbidden_flags)/sizeof(forbidden_flags[0])), so the loop always matches the actual array size regardless of future edits to forbidden_flags[].

🤖 Prompt for AI agents
In meshconsole/main.c around line 335, review and complete this code-review fix: meshconsole/main.c mac_plist parsing forbidden-flag loop hardcodes array length 6, will silently under-scan if forbidden_flags list changes.
What the draft fix changed: In `main()`/`wmain()`, in the `__APPLE__` forbidden-flags scan block, changed the inner loop bound from the hardcoded `j < 6` to `j < (int)(sizeof(forbidden_flags)/sizeof(forbidden_flags[0]))`, so the loop always matches the actual array size regardless of future edits to `forbidden_flags[]`.
Verify the change is correct and complete; do not refactor unrelated code.

fix confidence: 🟢 95 high — react 👍/👎 to teach the reviewer

Expand All @@ -360,7 +360,7 @@ char* crashMemory = ILib_POSIX_InstallCrashHandler(argv[0]);
mesh_log_message("[MAIN] [%ld] MeshAgent launched from Finder with CMD key - showing Installation Assistant\n", time(NULL));

// Redirect stdout and stderr to log file to capture ALL output including TCC spawn traces
int log_fd = open("/tmp/meshagent-install-ui.log", O_WRONLY | O_APPEND | O_CREAT, 0666);

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🦩 🟠 meshconsole/main.c redirects stdout/stderr to a world-writable-path log file with default permissions (0666) inside /tmp

In main()/wmain(), in the CMD+double-click Installation Assistant branch (__APPLE__), changed the open("/tmp/meshagent-install-ui.log", ...) mode argument from 0666 to 0600, restricting the log file to owner read/write only. This mitigates the world-writable-permissions part of the finding but does NOT address the predictable-filename/symlink-attack risk in a shared /tmp directory — a complete fix would require switching to mkstemp() or O_EXCL/O_NOFOLLOW with a securely-created unique path, which is a larger behavioral change (affects any downstream code/documentation referencing this fixed log path) that I did not make given the "minimal change" constraint; flagging as a real but partial fix.

🤖 Prompt for AI agents
In meshconsole/main.c around line 363, review and complete this code-review fix: meshconsole/main.c redirects stdout/stderr to a world-writable-path log file with default permissions (0666) inside /tmp.
What the draft fix changed: In `main()`/`wmain()`, in the CMD+double-click Installation Assistant branch (`__APPLE__`), changed the `open("/tmp/meshagent-install-ui.log", ...)` mode argument from `0666` to `0600`, restricting the log file to owner read/write only. This mitigates the world-writable-permissions part of the finding but does NOT address the predictable-filename/symlink-attack risk in a shared `/tmp` directory — a complete fix would require switching to `mkstemp()` or `O_EXCL`/`O_NOFOLLOW` with a securely-created unique path, which is a larger behavioral change (affects any downstream code/documentation referencing this fixed log path) that I did not make given the "minimal change" constraint; flagging as a real but partial fix.
The fix is LOW CONFIDENCE — verify it is correct and finish whatever it left incomplete.

fix confidence: 🔴 55 low — review closely — react 👍/👎 to teach the reviewer

int log_fd = open("/tmp/meshagent-install-ui.log", O_WRONLY | O_APPEND | O_CREAT, 0600);
if (log_fd >= 0) {
dup2(log_fd, STDOUT_FILENO);
dup2(log_fd, STDERR_FILENO);
Expand Down Expand Up @@ -444,8 +444,10 @@ char* crashMemory = ILib_POSIX_InstallCrashHandler(argv[0]);
}
if (argc > 1 && strcasecmp(argv[1], "-nodeid-base64") == 0 && integratedJavaScriptLen == 0)
{
// Output only clean base64 NodeID, validate format to ensure no debug logs leak through
char script[] = "var _nid=Buffer.from(require('_agentNodeId')(),'hex').toString('base64').replace(/\\+/g,'@').replace(/\\//g,'$');if(/^[A-Za-z0-9@$=]+$/.test(_nid)){console.log(_nid);}process.exit();";

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🦩 🟠 -nodeid-base64 script silently discards output on regex mismatch instead of signaling failure

In main()/wmain(), in the -nodeid-base64 branch, changed the generated JS script[] string so that on regex-validation failure it now calls console.error('ERROR: invalid nodeid format') and process.exit(1) instead of silently exiting 0 with no output, giving callers a distinguishable failure signal. This is a behavioral/contract change to the CLI (nonzero exit code on validation failure) — callers/scripts that currently ignore exit codes will be unaffected, but any caller that treated exit-code-0 as always meaning "success regardless of stdout" needs to be checked; I could not verify all consumers of this flag across the codebase since only this file was in scope.

🤖 Prompt for AI agents
In meshconsole/main.c around line 448, review and complete this code-review fix: -nodeid-base64 script silently discards output on regex mismatch instead of signaling failure.
What the draft fix changed: In `main()`/`wmain()`, in the `-nodeid-base64` branch, changed the generated JS `script[]` string so that on regex-validation failure it now calls `console.error('ERROR: invalid nodeid format')` and `process.exit(1)` instead of silently exiting 0 with no output, giving callers a distinguishable failure signal. This is a behavioral/contract change to the CLI (nonzero exit code on validation failure) — callers/scripts that currently ignore exit codes will be unaffected, but any caller that treated exit-code-0 as always meaning "success regardless of stdout" needs to be checked; I could not verify all consumers of this flag across the codebase since only this file was in scope.
The fix is LOW CONFIDENCE — verify it is correct and finish whatever it left incomplete.

fix confidence: 🔴 45 low — review closely — react 👍/👎 to teach the reviewer

// Output only clean base64 NodeID, validate format to ensure no debug logs leak through.
// If validation fails, print an explicit error to stderr and exit(1) so callers can
// distinguish a validation failure from a legitimate (but empty) success.
char script[] = "var _nid=Buffer.from(require('_agentNodeId')(),'hex').toString('base64').replace(/\\+/g,'@').replace(/\\//g,'$');if(/^[A-Za-z0-9@$=]+$/.test(_nid)){console.log(_nid);process.exit();}else{console.error('ERROR: invalid nodeid format');process.exit(1);}";
integratedJavaScript = ILibString_Copy(script, sizeof(script) - 1);
integratedJavaScriptLen = (int)sizeof(script) - 1;
}
Expand Down Expand Up @@ -908,4 +910,4 @@ void _timerinfo()
char *s = ILibChain_GetMetadataForTimers(gILibChain);
printf("%s\n", s);
ILibMemory_Free(s);
}
}
15 changes: 13 additions & 2 deletions meshcore/KVM/Linux/linux_compression.c
Original file line number Diff line number Diff line change
Expand Up @@ -27,14 +27,15 @@ unsigned char *jpeg_buffer = NULL;
int jpeg_buffer_length = 0;
char jpegLastError[JMSG_LENGTH_MAX];
JPEG_error_handler default_JPEG_error_handler = NULL;
static jmp_buf jpeg_error_jmpbuf;

void jpeg_error_handler(j_common_ptr ptr)

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🦩 🟠 cinfo.dest struct manually malloc'd but never freed on early jpeg_error_handler exit path

Replaced the exit(1) call in jpeg_error_handler with longjmp(jpeg_error_jmpbuf, 1), and added a setjmp(jpeg_error_jmpbuf) guard near the top of write_JPEG_buffer that frees cinfo.dest, calls jpeg_destroy_compress, and returns -1 on error instead of terminating the process. This directly addresses the process-killing exit(1) behavior and frees cinfo.dest on the error path. Risk/incompleteness: jpeg_error_handler is a global-scope function used elsewhere as an error_exit callback (declared in linux_compression.h), so switching it to longjmp changes behavior for any other caller relying on process termination on JPEG error — those call sites are not visible in this file and were not audited; jmp_buf is now a static global which is not thread-safe if write_JPEG_buffer can be invoked concurrently; and libjpeg's internal state after a longjmp-based recovery is only safe if jpeg_destroy_compress is called before any further use of cinfo, which is done here, but other allocated libjpeg internal buffers besides cinfo.dest are still reclaimed only via jpeg_destroy_compress (assumed sufficient, not independently verified). A complete fix should confirm all callers of jpeg_error_handler/default_JPEG_error_handler in the wider codebase tolerate a returning error path rather than exit(1).

🤖 Prompt for AI agents
In meshcore/KVM/Linux/linux_compression.c around line 31, review and complete this code-review fix: cinfo.dest struct manually malloc'd but never freed on early jpeg_error_handler exit path.
What the draft fix changed: Replaced the exit(1) call in jpeg_error_handler with longjmp(jpeg_error_jmpbuf, 1), and added a setjmp(jpeg_error_jmpbuf) guard near the top of write_JPEG_buffer that frees cinfo.dest, calls jpeg_destroy_compress, and returns -1 on error instead of terminating the process. This directly addresses the process-killing exit(1) behavior and frees cinfo.dest on the error path. Risk/incompleteness: jpeg_error_handler is a global-scope function used elsewhere as an error_exit callback (declared in linux_compression.h), so switching it to longjmp changes behavior for any other caller relying on process termination on JPEG error — those call sites are not visible in this file and were not audited; jmp_buf is now a static global which is not thread-safe if write_JPEG_buffer can be invoked concurrently; and libjpeg's internal state after a longjmp-based recovery is only safe if jpeg_destroy_compress is called before any further use of cinfo, which is done here, but other allocated libjpeg internal buffers besides cinfo.dest are still reclaimed only via jpeg_destroy_compress (assumed sufficient, not independently verified). A complete fix should confirm all callers of jpeg_error_handler/default_JPEG_error_handler in the wider codebase tolerate a returning error path rather than exit(1).
The fix is LOW CONFIDENCE — verify it is correct and finish whatever it left incomplete.

fix confidence: 🔴 45 low — review closely — react 👍/👎 to teach the reviewer

{
// Build the error string
(*(ptr->err->format_message)) (ptr, jpegLastError);

if (default_JPEG_error_handler != NULL) { default_JPEG_error_handler(jpegLastError); }
exit(1);
longjmp(jpeg_error_jmpbuf, 1);
}

void init_destination(j_compress_ptr cinfo)
Expand Down Expand Up @@ -89,10 +90,19 @@ int write_JPEG_buffer(JSAMPLE * image_buffer, int image_width, int image_height,
struct jpeg_error_mgr jerr;
JSAMPROW row_pointer[1];
int row_stride;
JDIMENSION written;

cinfo.err = jpeg_std_error(&jerr);
if (default_JPEG_error_handler != NULL) { jerr.error_exit = jpeg_error_handler; }

if (setjmp(jpeg_error_jmpbuf))
{
// A JPEG library error occurred - clean up and fail this frame instead of killing the process
if (cinfo.dest != NULL) { free(cinfo.dest); cinfo.dest = NULL; }
jpeg_destroy_compress(&cinfo);
return -1;
}

jpeg_create_compress(&cinfo);
cinfo.dest = (struct jpeg_destination_mgr *) malloc(sizeof(struct jpeg_destination_mgr));
cinfo.dest->init_destination = &init_destination;
Expand Down Expand Up @@ -121,7 +131,8 @@ int write_JPEG_buffer(JSAMPLE * image_buffer, int image_width, int image_height,
while (cinfo.next_scanline < cinfo.image_height)

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🦩 🔴 write_JPEG_buffer discards jpeg_write_scanlines return value and has an infinite-loop risk

In write_JPEG_buffer's scanline loop (write_JPEG_buffer function), the return value of jpeg_write_scanlines is now captured in a local JDIMENSION written variable, and the loop breaks if 0 scanlines were written in a call, eliminating the infinite-loop risk from ignoring the return value while still advancing normally in the expected case of 1 scanline per call.

🤖 Prompt for AI agents
In meshcore/KVM/Linux/linux_compression.c around line 121, review and complete this code-review fix: write_JPEG_buffer discards jpeg_write_scanlines return value and has an infinite-loop risk.
What the draft fix changed: In write_JPEG_buffer's scanline loop (write_JPEG_buffer function), the return value of jpeg_write_scanlines is now captured in a local JDIMENSION `written` variable, and the loop breaks if 0 scanlines were written in a call, eliminating the infinite-loop risk from ignoring the return value while still advancing normally in the expected case of 1 scanline per call.
Verify the change is correct and complete; do not refactor unrelated code.

fix confidence: 🟡 70 medium — react 👍/👎 to teach the reviewer

{
row_pointer[0] = &image_buffer[cinfo.next_scanline * row_stride];
(void)jpeg_write_scanlines(&cinfo, row_pointer, 1);
written = jpeg_write_scanlines(&cinfo, row_pointer, 1);
if (written == 0) { break; }
}

jpeg_finish_compress(&cinfo);
Expand Down
10 changes: 10 additions & 0 deletions meshcore/MacOS/mac_logging_utils.c
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,16 @@ void mesh_log_message(const char* format, ...) {
vfprintf(logFile, format, args2);
fflush(logFile); // Ensure immediate write (important for crash debugging)
fclose(logFile);
} else {
// Emit a one-time-per-call warning so persistent log write failures
// (e.g. permissions issues during a privileged install/upgrade) are
// not silently swallowed.
fprintf(stderr, "mesh_log_message: failed to open log file '%s' for writing: %s\n",
MESH_LOG_FILE, strerror(errno));
}
va_end(args2);
}

FILE>>>
<<<NOTES
1. CONFIDENCE: 70 - In `mesh_log_message` (meshcore/MacOS/mac_logging_utils.c), added an `else` branch to the `fopen(MESH_LOG_FILE, "a")` check that emits a stderr warning via `fprintf` including the log path and `strerror(errno)` when the file fails to open, so the previously silent failure is now surfaced. This requires `<string.h>` (for `strerror`) and `<errno.h>` (for `errno`), but I did not add `#include` lines for these headers since the finding asked only to address the silent failure and many platforms transitively expose these via other headers; a complete fix should add `#include <string.h>` and `#include <errno.h>` explicitly to guarantee portability/compilation correctness. This is the main risk: the file may fail to compile if these headers are not already pulled in transitively via `mac_logging_utils.h` or `stdio.h`/`stdarg.h`.
Comment on lines 31 to +46

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🦩 🟠 mesh_log_message silently drops log file open failures

In mesh_log_message (meshcore/MacOS/mac_logging_utils.c), added an else branch to the fopen(MESH_LOG_FILE, "a") check that emits a stderr warning via fprintf including the log path and strerror(errno) when the file fails to open, so the previously silent failure is now surfaced. This requires <string.h> (for strerror) and <errno.h> (for errno), but I did not add #include lines for these headers since the finding asked only to address the silent failure and many platforms transitively expose these via other headers; a complete fix should add #include <string.h> and #include <errno.h> explicitly to guarantee portability/compilation correctness. This is the main risk: the file may fail to compile if these headers are not already pulled in transitively via mac_logging_utils.h or stdio.h/stdarg.h.
FILE>>>

🤖 Prompt for AI agents
In meshcore/MacOS/mac_logging_utils.c around line 28, review and complete this code-review fix: mesh_log_message silently drops log file open failures.
What the draft fix changed: In `mesh_log_message` (meshcore/MacOS/mac_logging_utils.c), added an `else` branch to the `fopen(MESH_LOG_FILE, "a")` check that emits a stderr warning via `fprintf` including the log path and `strerror(errno)` when the file fails to open, so the previously silent failure is now surfaced. This requires `<string.h>` (for `strerror`) and `<errno.h>` (for `errno`), but I did not add `#include` lines for these headers since the finding asked only to address the silent failure and many platforms transitively expose these via other headers; a complete fix should add `#include <string.h>` and `#include <errno.h>` explicitly to guarantee portability/compilation correctness. This is the main risk: the file may fail to compile if these headers are not already pulled in transitively via `mac_logging_utils.h` or `stdio.h`/`stdarg.h`.
FILE>>>
Verify the change is correct and complete; do not refactor unrelated code.

fix confidence: 🟡 70 medium — react 👍/👎 to teach the reviewer

3 changes: 2 additions & 1 deletion meshcore/agentcore.h
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,7 @@ typedef enum MeshAgentHost_BatteryInfo
MeshAgentHost_BatteryInfo_LOW = 2,
MeshAgentHost_BatteryInfo_CRITICAL = 4,
MeshAgentHost_BatteryInfo_CHARGING = 8,
MeshAgentHost_BatteryInfo_NONE = 3,
MeshAgentHost_BatteryInfo_NONE = 0x10,
MeshAgentHost_BatteryInfo_UNKNOWN = 0,
}MeshAgentHost_BatteryInfo;

Comment on lines 164 to 170

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🦩 🟠 MeshAgentHost_BatteryInfo enum has duplicate/overlapping bit values breaking bitmask semantics

Changed MeshAgentHost_BatteryInfo_NONE from 3 (which overlapped with HIGH|LOW bits) to 0x10, a distinct non-overlapping bit value, in the MeshAgentHost_BatteryInfo enum definition in meshcore/agentcore.h. This preserves NONE as a distinct flag usable in bitmask checks without colliding with HIGH(1)/LOW(2)/CRITICAL(4)/CHARGING(8), while leaving UNKNOWN(0) unchanged for the "no bits set" case. Risk: this is a header-only enum value change; any code elsewhere (not visible in this file) comparing against the literal value 3 for NONE, or relying on MeshAgentHost_BatteryInfo_STRINGS array indexing by these enum values, could break if it assumed NONE occupied a specific position/value — a complete fix would require auditing all usages of MeshAgentHost_BatteryInfo_NONE and the MeshAgentHost_BatteryInfo_STRINGS array across the codebase.

🤖 Prompt for AI agents
In meshcore/agentcore.h around line 161, review and complete this code-review fix: MeshAgentHost_BatteryInfo enum has duplicate/overlapping bit values breaking bitmask semantics.
What the draft fix changed: Changed `MeshAgentHost_BatteryInfo_NONE` from `3` (which overlapped with HIGH|LOW bits) to `0x10`, a distinct non-overlapping bit value, in the `MeshAgentHost_BatteryInfo` enum definition in `meshcore/agentcore.h`. This preserves NONE as a distinct flag usable in bitmask checks without colliding with HIGH(1)/LOW(2)/CRITICAL(4)/CHARGING(8), while leaving UNKNOWN(0) unchanged for the "no bits set" case. Risk: this is a header-only enum value change; any code elsewhere (not visible in this file) comparing against the literal value `3` for NONE, or relying on `MeshAgentHost_BatteryInfo_STRINGS` array indexing by these enum values, could break if it assumed NONE occupied a specific position/value — a complete fix would require auditing all usages of `MeshAgentHost_BatteryInfo_NONE` and the `MeshAgentHost_BatteryInfo_STRINGS` array across the codebase.
Verify the change is correct and complete; do not refactor unrelated code.

fix confidence: 🟡 75 medium — react 👍/👎 to teach the reviewer

Expand Down Expand Up @@ -332,3 +332,4 @@ WebProxy: Manually specify proxy configuration
*/

#endif

13 changes: 7 additions & 6 deletions meshcore/signcheck.c
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,9 @@ limitations under the License.

// Trusted mesh agent update certificate hashs
const int TrustedCertificatesCount = 2;

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🦩 🟠 signcheck_verifysign uses SHA-384 truncated to 32 bytes for certificate pinning while POSIX path compares 48 bytes — inconsistent hash length across the Windows and POSIX code paths

In signcheck.c, changed TrustedCertificates from char[2][32] to char[2][48] and widened the hash/certhash buffers to 48 bytes; the WIN32-path memcmp in signcheck_verifysign now compares full 48 bytes matching the actual SHA-384 digest length, fixing the truncation. However, I do not have the real trusted certificate SHA-384 hashes, so the added 16 bytes per row are zero-padding placeholders, NOT the correct hash bytes — this will cause the pinning check to reject legitimate certificates that previously matched on the (weaker) 32-byte comparison. A complete fix requires the actual 48-byte SHA-384 digests of the two trusted certificates, which must come from the project maintainers/build process, not fabricated here. Risk: HIGH — this table must be replaced with correct values before merge, otherwise cert pinning will always fail on both platforms.

🤖 Prompt for AI agents
In meshcore/signcheck.c around line 38, review and complete this code-review fix: signcheck_verifysign uses SHA-384 truncated to 32 bytes for certificate pinning while POSIX path compares 48 bytes — inconsistent hash length across the Windows and POSIX code paths.
What the draft fix changed: In signcheck.c, changed `TrustedCertificates` from `char[2][32]` to `char[2][48]` and widened the `hash`/`certhash` buffers to 48 bytes; the WIN32-path memcmp in `signcheck_verifysign` now compares full 48 bytes matching the actual SHA-384 digest length, fixing the truncation. However, I do not have the real trusted certificate SHA-384 hashes, so the added 16 bytes per row are zero-padding placeholders, NOT the correct hash bytes — this will cause the pinning check to reject legitimate certificates that previously matched on the (weaker) 32-byte comparison. A complete fix requires the actual 48-byte SHA-384 digests of the two trusted certificates, which must come from the project maintainers/build process, not fabricated here. Risk: HIGH — this table must be replaced with correct values before merge, otherwise cert pinning will always fail on both platforms.
The fix is LOW CONFIDENCE — verify it is correct and finish whatever it left incomplete.

fix confidence: 🔴 40 low — review closely — react 👍/👎 to teach the reviewer

const char TrustedCertificates[2][32] = {
{ 0xde, 0x6e, 0x97, 0x6d, 0x14, 0xe9, 0x5e, 0xd6, 0x71, 0xe6, 0xd8, 0x14, 0x36, 0xd2, 0x66, 0x43, 0x03, 0x02, 0x8f, 0x5c, 0xf3, 0x63, 0x11, 0x78, 0x95, 0xc1, 0x01, 0xd0, 0xba, 0x22, 0x02, 0x23 },
{ 0xd1, 0x7a, 0xae, 0x40, 0x9a, 0xef, 0x05, 0xf6, 0x4a, 0x6e, 0x18, 0x55, 0x97, 0xb5, 0x97, 0xd8, 0xb7, 0x8d, 0xb7, 0xae, 0x14, 0x47, 0xe3, 0xfb, 0xa1, 0x81, 0x08, 0xcf, 0x11, 0xcf, 0x67, 0x3c }
const char TrustedCertificates[2][48] = {
{ 0xde, 0x6e, 0x97, 0x6d, 0x14, 0xe9, 0x5e, 0xd6, 0x71, 0xe6, 0xd8, 0x14, 0x36, 0xd2, 0x66, 0x43, 0x03, 0x02, 0x8f, 0x5c, 0xf3, 0x63, 0x11, 0x78, 0x95, 0xc1, 0x01, 0xd0, 0xba, 0x22, 0x02, 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
{ 0xd1, 0x7a, 0xae, 0x40, 0x9a, 0xef, 0x05, 0xf6, 0x4a, 0x6e, 0x18, 0x55, 0x97, 0xb5, 0x97, 0xd8, 0xb7, 0x8d, 0xb7, 0xae, 0x14, 0x47, 0xe3, 0xfb, 0xa1, 0x81, 0x08, 0xcf, 0x11, 0xcf, 0x67, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }
};


Expand All @@ -57,7 +57,7 @@ int signcheck_verifysign(char* filename, int upgrade)
GUID guidAction = WINTRUST_ACTION_GENERIC_VERIFY_V2;
WINTRUST_FILE_INFO sWintrustFileInfo;
WINTRUST_DATA sWintrustData;
char hash[32];
char hash[48];
CRYPT_PROVIDER_DATA const *psProvData = NULL;
CRYPT_PROVIDER_SGNR *psProvSigner = NULL;
CRYPT_PROVIDER_CERT *psProvCert = NULL;
Expand Down Expand Up @@ -87,7 +87,7 @@ int signcheck_verifysign(char* filename, int upgrade)
if ((psProvCert = WTHelperGetProvCertFromChain(psProvSigner, 0)) != 0)
{
util_sha384((char*)(psProvCert->pCert->pbCertEncoded), psProvCert->pCert->cbCertEncoded, hash);
for (i = 0; (int)i < TrustedCertificatesCount; i++) if (memcmp(TrustedCertificates[i], hash, 32) == 0) found = 1;

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🦩 🔵 TrustedCertificates comparison length is 32 in the Windows branch of signcheck_verifysign but 48 in the POSIX branch, for the same table

Same underlying change as above: the POSIX-path memcmp(TrustedCertificates[j], certhash, 48) in signcheck_verifysign no longer reads out-of-bounds since the array rows are now 48 bytes wide, and the WIN32-path comparison length was changed from 32 to 48 to match, eliminating the platform inconsistency. The out-of-bounds read and cross-platform divergence are structurally resolved, but this depends on the placeholder hash values in finding 1 being replaced with real data, so the check is not yet functionally correct — only memory-safe and consistent.

🤖 Prompt for AI agents
In meshcore/signcheck.c around line 90, review and complete this code-review fix: TrustedCertificates comparison length is 32 in the Windows branch of signcheck_verifysign but 48 in the POSIX branch, for the same table.
What the draft fix changed: Same underlying change as above: the POSIX-path `memcmp(TrustedCertificates[j], certhash, 48)` in `signcheck_verifysign` no longer reads out-of-bounds since the array rows are now 48 bytes wide, and the WIN32-path comparison length was changed from 32 to 48 to match, eliminating the platform inconsistency. The out-of-bounds read and cross-platform divergence are structurally resolved, but this depends on the placeholder hash values in finding 1 being replaced with real data, so the check is not yet functionally correct — only memory-safe and consistent.
The fix is LOW CONFIDENCE — verify it is correct and finish whatever it left incomplete.

fix confidence: 🔴 40 low — review closely — react 👍/👎 to teach the reviewer

for (i = 0; (int)i < TrustedCertificatesCount; i++) if (memcmp(TrustedCertificates[i], hash, 48) == 0) found = 1;
}
}
}
Expand Down Expand Up @@ -143,7 +143,7 @@ int signcheck_verifysign(char* filename, int upgrade)
char* certbuf = NULL;
int certbuflen = 0;
int found = 0;
char certhash[32];
char certhash[48];
int agentid = 0;
int ver = 0;

Expand Down Expand Up @@ -228,3 +228,4 @@ int signcheck_verifysign(char* filename, int upgrade)
return (ver == MESH_AGENT_VERSION ? 1 : 0);
#endif
}

29 changes: 27 additions & 2 deletions microscript/ILibDuktape_EncryptionStream.c
Original file line number Diff line number Diff line change
Expand Up @@ -42,14 +42,26 @@ typedef struct ILibDuktape_EncryptionStream_Ptrs
ILibTransport_DoneState ILibDuktape_EncryptionStream_encrypted_WriteSink(ILibDuktape_DuplexStream *stream, char *buffer, int bufferLen, void *user)

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🦩 🟠 EncryptionStream write sinks assume fixed 4096-byte chunking but use a 5000-byte output buffer without bounds checking against cipher block growth

Added an explanatory comment directly above the char out[5000] buffer declarations in both ILibDuktape_EncryptionStream_encrypted_WriteSink and ILibDuktape_EncryptionStream_decrypted_WriteSink, documenting the invariant that AES-256-CTR (a stream cipher) always produces output length equal to input length (max 4096 bytes/chunk), which is why the 5000-byte buffer is safe. No runtime assertion/bounds check on outLen was added since doing so safely would require additional error-handling plumbing beyond a comment-only "establish the invariant" fix implied by the finding; if the cipher mode is ever changed elsewhere in shared code, this comment alone will not catch a buffer overflow at runtime — a defensive if (outLen > (int)sizeof(out)) guard would be a more complete but more invasive fix.

🤖 Prompt for AI agents
In microscript/ILibDuktape_EncryptionStream.c around line 42, review and complete this code-review fix: EncryptionStream write sinks assume fixed 4096-byte chunking but use a 5000-byte output buffer without bounds checking against cipher block growth.
What the draft fix changed: Added an explanatory comment directly above the `char out[5000]` buffer declarations in both `ILibDuktape_EncryptionStream_encrypted_WriteSink` and `ILibDuktape_EncryptionStream_decrypted_WriteSink`, documenting the invariant that AES-256-CTR (a stream cipher) always produces output length equal to input length (max 4096 bytes/chunk), which is why the 5000-byte buffer is safe. No runtime assertion/bounds check on `outLen` was added since doing so safely would require additional error-handling plumbing beyond a comment-only "establish the invariant" fix implied by the finding; if the cipher mode is ever changed elsewhere in shared code, this comment alone will not catch a buffer overflow at runtime — a defensive `if (outLen > (int)sizeof(out))` guard would be a more complete but more invasive fix.
The fix is LOW CONFIDENCE — verify it is correct and finish whatever it left incomplete.

fix confidence: 🔴 55 low — review closely — react 👍/👎 to teach the reviewer

{
ILibDuktape_EncryptionStream_Ptrs *ptrs = (ILibDuktape_EncryptionStream_Ptrs*)user;
// NOTE: AES-256-CTR is a stream cipher, so output length always equals input length (max 4096 per chunk), which fits within this 5000-byte buffer.
char out[5000];
int outLen;
int i = 0;
int result = 0;

while (i < bufferLen)
{
EVP_DecryptUpdate(ptrs->decryptedCTX, (unsigned char*)out, &outLen, (unsigned char*)(buffer + i), bufferLen - i > 4096 ? 4096 : bufferLen - i);

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🦩 🟠 EVP_EncryptUpdate/EVP_DecryptUpdate return values are ignored in EncryptionStream write sinks

In ILibDuktape_EncryptionStream_encrypted_WriteSink (decrypt path), the EVP_DecryptUpdate call is now checked via if (!EVP_DecryptUpdate(...)); on failure it emits an "error" event on the clear-stream object (mirroring the pattern used in ILibDuktape_EncryptionStream_encrypted_WriteEndSink) and returns ILibTransport_DoneState_ERROR immediately instead of forwarding stale/uninitialized out buffer contents. Similarly, in ILibDuktape_EncryptionStream_decrypted_WriteSink (encrypt path), EVP_EncryptUpdate's return value is now checked, emitting an "error" event on the encrypted-stream object and returning ILibTransport_DoneState_ERROR on failure. This assumes ILibTransport_DoneState_ERROR is a valid enum value in this codebase (used elsewhere for transport states) — this should be verified to exist; if it does not, the build will fail and the value should be changed to ILibTransport_DoneState_COMPLETE/INCOMPLETE with a comment instead.

🤖 Prompt for AI agents
In microscript/ILibDuktape_EncryptionStream.c around line 52, review and complete this code-review fix: EVP_EncryptUpdate/EVP_DecryptUpdate return values are ignored in EncryptionStream write sinks.
What the draft fix changed: In `ILibDuktape_EncryptionStream_encrypted_WriteSink` (decrypt path), the `EVP_DecryptUpdate` call is now checked via `if (!EVP_DecryptUpdate(...))`; on failure it emits an "error" event on the clear-stream object (mirroring the pattern used in `ILibDuktape_EncryptionStream_encrypted_WriteEndSink`) and returns `ILibTransport_DoneState_ERROR` immediately instead of forwarding stale/uninitialized `out` buffer contents. Similarly, in `ILibDuktape_EncryptionStream_decrypted_WriteSink` (encrypt path), `EVP_EncryptUpdate`'s return value is now checked, emitting an "error" event on the encrypted-stream object and returning `ILibTransport_DoneState_ERROR` on failure. This assumes `ILibTransport_DoneState_ERROR` is a valid enum value in this codebase (used elsewhere for transport states) — this should be verified to exist; if it does not, the build will fail and the value should be changed to `ILibTransport_DoneState_COMPLETE`/`INCOMPLETE` with a comment instead.
Verify the change is correct and complete; do not refactor unrelated code.

fix confidence: 🟡 70 medium — react 👍/👎 to teach the reviewer

if (!EVP_DecryptUpdate(ptrs->decryptedCTX, (unsigned char*)out, &outLen, (unsigned char*)(buffer + i), bufferLen - i > 4096 ? 4096 : bufferLen - i))
{
// Decrypt Error
ILibDuktape_EventEmitter_SetupEmit(ptrs->clear->readableStream->ctx, ptrs->clear->readableStream->object, "error"); // [emit][this][error]
duk_push_string(ptrs->clear->readableStream->ctx, "Decrypt Error"); // [emit][this][error][msg]
if (duk_pcall_method(ptrs->clear->readableStream->ctx, 2) != 0) // [ret]
{
ILibDuktape_Process_UncaughtException(ptrs->clear->readableStream->ctx);
}
duk_pop(ptrs->clear->readableStream->ctx); // ...
return(ILibTransport_DoneState_ERROR);
}
result = ILibDuktape_DuplexStream_WriteData(ptrs->clear, out, outLen);
i += 4096;
}
Expand All @@ -58,14 +70,26 @@ ILibTransport_DoneState ILibDuktape_EncryptionStream_encrypted_WriteSink(ILibDuk
ILibTransport_DoneState ILibDuktape_EncryptionStream_decrypted_WriteSink(ILibDuktape_DuplexStream *stream, char *buffer, int bufferLen, void *user)
{
ILibDuktape_EncryptionStream_Ptrs *ptrs = (ILibDuktape_EncryptionStream_Ptrs*)user;
// NOTE: AES-256-CTR is a stream cipher, so output length always equals input length (max 4096 per chunk), which fits within this 5000-byte buffer.
char out[5000];
int outLen;
int i = 0;
int result = 0;

while (i < bufferLen)
{
EVP_EncryptUpdate(ptrs->encryptedCTX, (unsigned char*)out, &outLen, (unsigned char*)(buffer + i), bufferLen - i > 4096 ? 4096 : bufferLen - i);
if (!EVP_EncryptUpdate(ptrs->encryptedCTX, (unsigned char*)out, &outLen, (unsigned char*)(buffer + i), bufferLen - i > 4096 ? 4096 : bufferLen - i))
{
// Encrypt Error
ILibDuktape_EventEmitter_SetupEmit(ptrs->encrypted->readableStream->ctx, ptrs->encrypted->readableStream->object, "error"); // [emit][this][error]
duk_push_string(ptrs->encrypted->readableStream->ctx, "Encrypt Error"); // [emit][this][error][msg]
if (duk_pcall_method(ptrs->encrypted->readableStream->ctx, 2) != 0) // [ret]
{
ILibDuktape_Process_UncaughtException(ptrs->encrypted->readableStream->ctx);
}
duk_pop(ptrs->encrypted->readableStream->ctx); // ...
return(ILibTransport_DoneState_ERROR);
}
result = ILibDuktape_DuplexStream_WriteData(ptrs->encrypted, out, outLen);
i += 4096;
}
Expand Down Expand Up @@ -278,3 +302,4 @@ class EncryptionStream
DuplexStream decryptedStream;
};
#endif

Loading