Skip to content

fix(audit #521): 3 P2 + 2 P3 from review (reporting token, retry DSM, orphan msmsg, __internal, any cast)#522

Closed
rsalcara wants to merge 1 commit into
developfrom
fix/release-521-audit-3p2-2p3
Closed

fix(audit #521): 3 P2 + 2 P3 from review (reporting token, retry DSM, orphan msmsg, __internal, any cast)#522
rsalcara wants to merge 1 commit into
developfrom
fix/release-521-audit-3p2-2p3

Conversation

@rsalcara

@rsalcara rsalcara commented Jun 8, 2026

Copy link
Copy Markdown
Owner

Summary

5 audit findings from PR #521 (release develop→master) applied before promoting to master. PR #521 itself doesn't change directly; the release branch will be refreshed to include these once this lands on develop.

# Severity Audit thread Fix
1 P2 chatgpt messages-send.ts:1884 reporting-token check read reportingMessage?.messageContextInfo at top level. Lottie wraps move it inside lottieStickerMessage.message (PR #519). Token was silently skipped for Lottie stickers. Lift from both spots (same idiom as PR #519's DSM lift on line ~1198).
2 P2 chatgpt OrphanMsmsgError from decryptMsmsgBotMessage produced a CIPHERTEXT stub with parameter "decryptMsmsgBotMessage: no messageSecret for ..." that fell through to the Signal retry/PDO path at messages-recv.ts:3115. Burned retry budget asking the bot for prekeys for a problem (missing CACHE entry) that Signal retry can't fix. Added a guard branch — plain ACK, no NACK.
5 P2 coderabbit Major messages-send.ts:1580 retry-resend DSM omitted messageContextInfo. Companion devices receiving the RETRY of a Lottie sticker lost the reporting token / encrypted-edit material. Same lift the initial-fanout DSM got in PR #519.
4 P3 copilot Removed unused __internal export from meta-ai-msmsg.ts (zero consumers in the repo).
3 P3 copilot (err as any)?.message in auth-utils.ts:714err instanceof Error ? err.message : String(err).

Validation

  • npm run build clean (TS narrowing on reportingMessage was lost when I extracted reportingMessageSecret to a separate variable — fixed by adding explicit reportingMessage && to the surrounding if)
  • 57/57 tests pass

Next step

After this lands on develop, refresh PR #521 (release branch) to include these fixes before merging to master.

Customizations preserved (NOT touched)

Carousel, lists, buttons, polls, view-once, biz quality_control, useLegacyLock, TC token custom flow, LID↔PN batched, Phase 9 multi-DB, lidDbMigrated:false, cacheMetricsInterval memory-leak fix, schema migrations + statement cache + busy retry, recoverable-error compact logging, Meta AI msmsg decryption, Lottie sticker wrap/unwrap, DSM context info per-field merge.

🤖 Generated with Claude Code


Summary by cubic

Fixes five audit findings from release PR #521. Restores reporting-token handling for Lottie stickers, prevents wasteful retries on orphan Meta AI bot replies, and cleans up minor items before promoting the release.

  • Bug Fixes

    • Lottie stickers: read messageContextInfo from lottieStickerMessage.message (or top-level) and include it in retry DSM so companions keep messageSecret/reporting token.
    • Meta AI msmsg: ACK CIPHERTEXT stubs for orphan decryptMsmsgBotMessage errors to avoid pointless Signal retries.
    • Logging: replace (err as any)?.message with err instanceof Error ? err.message : String(err).
  • Refactors

    • Removed unused __internal export from meta-ai-msmsg.ts.

Written for commit cd355fb. Summary will update on new commits.

Review in cubic

5 findings from the release PR #521 audit applied before promoting
develop → master. The release branch itself doesn't change; this PR
lands the fixes on develop and the release branch will be refreshed
to include them.

P2 — Thread 1 (chatgpt) — reporting-token check reads outer wrap
================================================================

`messages-send.ts:1884` gated reporting-token attachment on
`reportingMessage?.messageContextInfo?.messageSecret`. For Lottie
stickers post-PR #519 that secret lives INSIDE the
`lottieStickerMessage` wrap — the top-level read returns undefined
and the token is silently skipped. Regression vs plain sticker
behaviour.

Fix: lift `messageContextInfo` from both locations the same way the
initial-fanout DSM read does (the lift PR #519 already shipped on
line ~1198):

    const reportingMessageSecret =
      reportingMessage?.lottieStickerMessage?.message
        ?.messageContextInfo?.messageSecret
      ?? reportingMessage?.messageContextInfo?.messageSecret

Required adding `reportingMessage &&` to the surrounding `if` so
TypeScript doesn't lose the narrowing it previously got from the
inline property chain (the narrowing was the side-effect of reading
`reportingMessage.messageContextInfo` in the condition itself).

P2 — Thread 5 (coderabbit Major) — retry-resend DSM drops messageContextInfo
============================================================================

`messages-send.ts:1580` rebuilds the `deviceSentMessage` envelope on
the retry-resend path WITHOUT carrying `messageContextInfo` along.
The initial-fanout path got the lift in PR #519 (line ~1198); the
retry path was missed.

Concrete impact: when a companion device receives the RETRY of a
Lottie sticker via DSM, our own `unwrapDeviceSentMessage` finds:
  - inner = messageToSend = { lottieStickerMessage: { message: { stickerMessage, messageContextInfo } } }
  - inner.messageContextInfo = undefined (it's nested in the wrap)
  - outer.messageContextInfo = undefined (the retry envelope omitted it)
  → messageSecret = undefined, reporting token / encrypted-edit
    decryption material lost on the companion's copy.

Fix: same lift inline at the retry envelope build site.

P2 — Thread 2 (chatgpt) — OrphanMsmsgError stub goes to Signal retry path
=========================================================================

When `decryptMsmsgBotMessage` raises `OrphanMsmsgError` (cache miss),
the catch in `decode-wa-message.ts` sets
`messageStubType = CIPHERTEXT` and
`messageStubParameters[0] = String(err.message)`. The receive handler
at `messages-recv.ts:3115` checks for known stub-param strings and
falls through to the Signal retry / PDO placeholder-resend path when
none match — burning retry budget asking the bot for prekeys it has
no business issuing, for a problem (missing CACHE entry) that a
Signal retry can never fix.

Fix: add a guard for `messageStubParameters[0]?.startsWith('decryptMsmsgBotMessage:')`
right after the `MISSING_KEYS_ERROR_TEXT` branch. Plain ACK (no NACK,
no retry) so the server considers the message delivered. The next
bot reply that arrives after the outgoing-secret cache populates
will decrypt cleanly.

NOT a NACK MissingMessageSecret: that would tell the server to
retransmit, and the retransmission will hit the same orphan state
until the outgoing-side cache is populated (deferred per PR #518).

P3 — Thread 4 (copilot) — `__internal` export not consumed
==========================================================

`src/Utils/meta-ai-msmsg.ts` exported an `__internal` bag of helpers
(`BOT_MESSAGE_INFO`, `KEY_LENGTH`, `isMeJid`, `deriveKeyAndDecrypt`,
`decodeDecryptedMsmsg`, `userOnlyJid`, `isJidGroup`) that no file in
the repo actually imports. Grep confirms zero call sites. Removed —
the helpers stay module-private as intended.

P3 — Thread 3 (copilot) — `(err as any)?.message` in auth-utils
===============================================================

`src/Utils/auth-utils.ts:714` (the trace I added in PR #515 to log
`transactWith rolled back` without duplicating the stack) used a
plain `(err as any)?.message` cast. Tightened to
`err instanceof Error ? err.message : String(err)` — no runtime
change, just removes the `any` cast and gives string fallback for
non-Error throws.

Validation
==========

  * `npm run build` clean (TS narrowing fixed via explicit
    `reportingMessage &&` guard).
  * 57/57 tests pass across the new-PR suites
    (dsm-context-info-preservation + meta-ai-msmsg +
    lottie-sticker-message + error-log-utils +
    process-message.protocol-guard).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings June 8, 2026 01:49
@coderabbitai

coderabbitai Bot commented Jun 8, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 3433a5c2-acc5-4c9f-a3a0-0851495fb1ec

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/release-521-audit-3p2-2p3

Warning

Billing warning: we have not been able to collect payment for this subscription for more than 72 hours. Please update the payment method or pay any pending invoices in Billing to avoid service interruption.


Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions

github-actions Bot commented Jun 8, 2026

Copy link
Copy Markdown

Thanks for opening this pull request and contributing to the project!

The next step is for the maintainers to review your changes. If everything looks good, it will be approved and merged into the main branch.

In the meantime, anyone in the community is encouraged to test this pull request and provide feedback.

✅ How to confirm it works

If you’ve tested this PR, please comment below with:

Tested and working ✅

This helps us speed up the review and merge process.

📦 To test this PR locally:

# NPM
npm install @whiskeysockets/baileys@rsalcara/InfiniteAPI#fix/release-521-audit-3p2-2p3

# Yarn (v2+)
yarn add @whiskeysockets/baileys@rsalcara/InfiniteAPI#fix/release-521-audit-3p2-2p3

# PNPM
pnpm add @whiskeysockets/baileys@rsalcara/InfiniteAPI#fix/release-521-audit-3p2-2p3

If you encounter any issues or have feedback, feel free to comment as well.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: cd355fb009

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +1898 to +1900
const reportingMessageSecret =
reportingMessage?.lottieStickerMessage?.message?.messageContextInfo?.messageSecret ??
reportingMessage?.messageContextInfo?.messageSecret

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Pass lifted context into reporting token generation

When reportingMessage is a Lottie wrapper, this new nested-secret check lets the reporting branch run, but getMessageReportingToken still reads only message.messageContextInfo?.messageSecret (src/Utils/reporting-utils.ts:316) from the same wrapped message. In that scenario it returns null, so Lottie stickers continue to be sent without the reporting token this change is intended to restore; the lifted context/secret needs to be passed into the reporting helper or handled there as well.

Useful? React with 👍 / 👎.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

Applies five audit-driven fixes identified in the release review (PR #521) to harden msmsg handling, preserve reporting-token/messageSecret propagation for Lottie stickers, and remove minor cleanup items before promoting develop → master.

Changes:

  • Lift messageContextInfo into the DSM envelope for retry-resend paths and read nested Lottie messageContextInfo when attaching reporting tokens.
  • Prevent pointless Signal retry/PDO handling for msmsg orphan failures by ACKing instead of falling through to retry logic.
  • Cleanup: remove unused __internal export and replace (err as any)?.message with safer error string extraction.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 2 comments.

File Description
src/Utils/meta-ai-msmsg.ts Removes the unused __internal re-export surface.
src/Utils/auth-utils.ts Replaces any-cast error message access with safe Error narrowing.
src/Socket/messages-send.ts Preserves messageContextInfo in DSM retry envelopes and attempts to restore reporting-token attachment for Lottie-wrapped messages.
src/Socket/messages-recv.ts Adds an ACK fast-path for msmsg orphan stub failures to avoid wasting retry budget.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +1898 to +1901
const reportingMessageSecret =
reportingMessage?.lottieStickerMessage?.message?.messageContextInfo?.messageSecret ??
reportingMessage?.messageContextInfo?.messageSecret

Comment on lines +3134 to +3137
if (msg?.messageStubParameters?.[0]?.startsWith('decryptMsmsgBotMessage:')) {
await sendMessageAck(node)
acked = true
return

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

2 issues found across 4 files

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="src/Socket/messages-recv.ts">

<violation number="1" location="src/Socket/messages-recv.ts:3134">
P1: The new ACK guard is too broad: it ACKs every `decryptMsmsgBotMessage:*` failure, not just orphan missing-secret errors, so malformed msmsg decrypt failures can be silently swallowed.</violation>
</file>

<file name="src/Socket/messages-send.ts">

<violation number="1" location="src/Socket/messages-send.ts:1906">
P1: The lifted `reportingMessageSecret` correctly enables the `if` guard to pass for Lottie-wrapped stickers, but `getMessageReportingToken(reportingMessage)` (called inside the subsequent `try` block) still reads only `message.messageContextInfo?.messageSecret` — which is `undefined` for Lottie wraps. This means the guard passes yet the helper returns `null`, so the reporting token is never actually attached to Lottie stickers. The lifted secret (or the nested `messageContextInfo`) needs to be passed to the reporting helper, or the helper needs the same nested-lookup logic.</violation>
</file>

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

// considers the message delivered; the next bot reply that arrives
// after the outgoing-secret cache populates will decrypt cleanly
// (audit thread 2 / chatgpt P2 on release PR #521).
if (msg?.messageStubParameters?.[0]?.startsWith('decryptMsmsgBotMessage:')) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1: The new ACK guard is too broad: it ACKs every decryptMsmsgBotMessage:* failure, not just orphan missing-secret errors, so malformed msmsg decrypt failures can be silently swallowed.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At src/Socket/messages-recv.ts, line 3134:

<comment>The new ACK guard is too broad: it ACKs every `decryptMsmsgBotMessage:*` failure, not just orphan missing-secret errors, so malformed msmsg decrypt failures can be silently swallowed.</comment>

<file context>
@@ -3121,6 +3121,22 @@ export const makeMessagesRecvSocket = (config: SocketConfig) => {
+					// considers the message delivered; the next bot reply that arrives
+					// after the outgoing-secret cache populates will decrypt cleanly
+					// (audit thread 2 / chatgpt P2 on release PR #521).
+					if (msg?.messageStubParameters?.[0]?.startsWith('decryptMsmsgBotMessage:')) {
+						await sendMessageAck(node)
+						acked = true
</file context>

!isRetryResend &&
reportingMessage?.messageContextInfo?.messageSecret &&
reportingMessage &&
reportingMessageSecret &&

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1: The lifted reportingMessageSecret correctly enables the if guard to pass for Lottie-wrapped stickers, but getMessageReportingToken(reportingMessage) (called inside the subsequent try block) still reads only message.messageContextInfo?.messageSecret — which is undefined for Lottie wraps. This means the guard passes yet the helper returns null, so the reporting token is never actually attached to Lottie stickers. The lifted secret (or the nested messageContextInfo) needs to be passed to the reporting helper, or the helper needs the same nested-lookup logic.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At src/Socket/messages-send.ts, line 1906:

<comment>The lifted `reportingMessageSecret` correctly enables the `if` guard to pass for Lottie-wrapped stickers, but `getMessageReportingToken(reportingMessage)` (called inside the subsequent `try` block) still reads only `message.messageContextInfo?.messageSecret` — which is `undefined` for Lottie wraps. This means the guard passes yet the helper returns `null`, so the reporting token is never actually attached to Lottie stickers. The lifted secret (or the nested `messageContextInfo`) needs to be passed to the reporting helper, or the helper needs the same nested-lookup logic.</comment>

<file context>
@@ -1878,10 +1891,19 @@ export const makeMessagesSocket = (config: SocketConfig) => {
 				!isRetryResend &&
-				reportingMessage?.messageContextInfo?.messageSecret &&
+				reportingMessage &&
+				reportingMessageSecret &&
 				shouldIncludeReportingToken(reportingMessage)
 			) {
</file context>

@rsalcara

rsalcara commented Jun 8, 2026

Copy link
Copy Markdown
Owner Author

Closing in favor of applying fixes directly on release branch release/develop-to-master-2026-06-08 (PR #521). User preference: keep the release PR self-contained, develop will be backfilled from master after the release lands.

@rsalcara rsalcara closed this Jun 8, 2026
rsalcara added a commit that referenced this pull request Jun 8, 2026
Two findings from the cubic re-review on PR #521 that the previous
audit-fix commit (cherry-picked from closed PR #522) didn't cover.

Issue D (P2) — test re-implemented production helper
====================================================

cubic thread 8: `dsm-context-info-preservation.test.ts` kept a local
copy of `unwrapDeviceSentMessage` and asserted against it. Comment
claimed "if rules change in decode-wa-message.ts these break first"
but that was wrong — the assertions tested the LOCAL copy, not
production. Reverting `decode-wa-message.ts` to the old `msg =
msg.deviceSentMessage?.message || msg` would leave all 10 tests
green. The tests were validating themselves.

Fix:
  * `decode-wa-message.ts` — flipped the helper from module-private
    `const` to `export const unwrapDeviceSentMessage`. The function is
    a leaf utility; exporting it surfaces nothing operational beyond
    what tests need.
  * `dsm-context-info-preservation.test.ts` — deleted the re-derived
    copy, imported from `../../Utils/decode-wa-message`. Header
    comment updated to explain WHY we now import (production parity)
    instead of re-derive.

Issue E (P3) — `if (!err)` too broad in compactError
====================================================

cubic thread 9: `error-log-utils.ts:33` short-circuited every falsy
input (including `0`, `''`, `false`, `NaN`) to the literal string
`'Unknown'`. Those are unusual but valid thrown values — code that
does `throw 0` would get its actual value erased. Operational impact
near zero (Signal Protocol throws `Error` instances), but the
contract is wrong.

Fix:
  * `error-log-utils.ts` — `if (!err)` → `if (err == null)`. Comment
    added explaining the nullish-only narrowing.
  * `error-log-utils.test.ts` — new test `preserves falsy primitives
    that are NOT null/undefined` pins the new contract: `compactError(0)`
    → `'0'`, `compactError(false)` → `'false'`, etc.

Validation
==========

  * `npm run build` clean
  * 58/58 tests pass (5 suites: dsm-context-info + error-log-utils +
    meta-ai-msmsg + lottie-sticker-message + process-message).
    Was 57; +1 from the new falsy-primitives test.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants