While auditing a Rails application, I reviewed its report-sharing flow. The application generated a URL that a user could send to a recipient to grant access to a document. If the URL reached the wrong person or access needed to end, the product needed a way to invalidate it.
The repository appeared to cover that case. A comment described the link as revocable, and a method regenerated its token, which should have made the previous URL unusable. The product, however, offered no revoke button, and nothing invoked the method.
Reading only the code suggested an obvious conclusion: revocation was broken. Following the product raised a different possibility: the feature might never have existed.
A feature that existed only in the repository
I restarted from the entry point. A route created the share, the controller prepared the link, and the interface let the user send it. The flow ended there, with no action to invalidate the URL and no screen for generating a replacement.
The regeneration method completed no user flow. Its name and comment described a coherent capability, but the method remained disconnected from the product. That distinction matters during an audit: a broken revocation feature means users could rely on behavior that failed, while an orphaned implementation points to work that was abandoned or never finished.
The likeliest explanation was a client request taken too literally. “We need to revoke a link” sounds like a need, but it already describes a solution. The underlying problem may have been a link sent to the wrong recipient, access that lasted too long, or poorly defined permissions. None of those cases had been framed, and the method remained after the subject was dropped.
The same mismatch distorts estimates. A team reading the repository may price an enhancement as if revocation already existed, then discover that permissions, interface design, and the behavior of previously issued links still need to be defined.
Proving the code is unreachable
Finding no callers is not always enough in a Rails application. A callback, an interpolated name, public_send, or a background job far from the model may still invoke a method. I checked the code from the entry points the product actually used.
- reproduce link creation and use through the interface;
- trace the route, controller, views, and background jobs;
- search for direct references to the method and token name;
- inspect dynamic calls that a text search could miss;
- instrument the method temporarily if production traffic leaves any doubt.
That evidence supports a narrow deletion: the method, its comment, and tests that cover only the orphaned implementation can disappear together. Tests around the sharing flow then confirm that creating and opening a link still work. Git retains the previous implementation if the investigation turns out to be incomplete, without forcing the repository to present it as current code.
Delete the code, preserve the need
The dead method did not make revocation available, but the need remained valid. Deleting both together would conflate two separate decisions: cleaning the repository now and deciding whether the product should support revocation.
A real feature ticket still needs to define who can revoke a link, what its recipient sees after invalidation, whether the product creates a replacement automatically, and how the interface confirms the operation. Keeping an unused method answers none of those questions and merely makes the work look almost complete.
The orphaned code can be deleted immediately while the need enters the roadmap with its actual scope. If revocation is prioritized later, its implementation can start from the expected user flow instead of a method discovered by accident.
What the audit should conclude
The report should claim neither a fixed vulnerability nor a repaired feature. It should establish that links had never been revocable, the regeneration method had no callers, and deleting it did not change the product’s behavior.
That conclusion leaves two useful artifacts: evidence supporting the cleanup and a product need that can be prioritized separately. The next reader will no longer mistake an abandoned intention for an available capability.