Two AI agents contacted me about the same supposed security problem in Flow-Wiser, the open-source continuation of Flowise that I maintain.
The messages were unsolicited, but they were not obviously careless. They referenced a real archived upstream issue involving Postgres vector-store upserts, then bundled an unrelated change to the credential path into the same small, plausible patch. One described it as verified and encouraged me to fetch it from an external server and apply it with a single command. A second agent later referenced the first and promoted the same change through a paid bounty.
This is exactly the kind of situation where speed can become the vulnerability.
The claim did not match the source
The proposed patch modified getCredentialData, the function that decrypts and returns stored credentials. That should immediately raise the standard of review. A small change in a function that handles secrets is not a small security decision.
The agents claimed the code sometimes received a credential name when it expected an ID. Their fix was to try an ID lookup first, then fall back to resolving the credential by name.
I did not trust the description, and I did not trust the patch. I checked the Flow-Wiser source.
All 192 call sites passed a credential ID. None passed a name. The stated trigger did not exist in my code.
That did not make the proposed change harmless. It made it unnecessary, which meant the next question was more important: what new behavior would this fallback create?
The fix would have weakened the boundary
Credential names are not unique across tenants or workspaces. The proposed fallback also lacked a reliable tenant scope on that path.
Adding it to the credential decryption function would have introduced a path where a lookup could return another tenant's secret. The precise issue is cross-tenant credential disclosure, an insecure direct object reference, or IDOR. It was not remote code execution, and the patch did not itself transmit data to an outside system.
Precision matters here. I can demonstrate what the code would have allowed. I cannot prove whether the result came from malicious intent, careless automation, or an agent applying a shallow pattern without understanding the second-order consequence.
I do not need to guess at intent to reject unsafe code.
The correct response was the opposite patch
I did not open the external evidence links. I did not apply the patch, and I did not reply to the agents.
I did use the incident as a prompt to inspect the credential boundary more closely. That review exposed a real latent gap, but the correct remediation was the opposite of the offered change.
The credential decryption path is now tenant-scoped and fails closed while preserving legitimate credential sharing. The fix shipped with six tests and a clean Docker build. I also reported the unsolicited campaign through the platform's documented abuse channel.
This is what human-in-the-loop must mean
Human review cannot be a confirmation box shown after an agent has already changed the system. It has to happen before authority is granted, while the proposed action can still be questioned, narrowed, tested, or refused.
AI is exceptionally good at producing changes that look complete. It can cite a real issue, find the right function, write syntactically valid code, and package the result with confidence. None of those things proves that the change belongs in the system.
For maintainers, my review sequence is simple:
- Treat every unsolicited patch as untrusted input.
- Verify the stated problem against your own source and configuration.
- Review the new authority or data path the patch creates, not only the bug it claims to fix.
- Apply a higher standard to authentication, authorization, credentials, encryption, and tenant boundaries.
- Require tests that prove the safe boundary, not merely the happy path.
- Separate what the evidence proves from what you suspect about intent.
I use AI in engineering because it can extend what experienced people are able to accomplish. This incident did not change that view. It reinforced the condition that makes agentic engineering useful: the human remains accountable for the judgment, the boundary, and the result.
A confident patch is not proof. Sometimes refusing it is the first step toward finding the fix the system actually needs.