That Vibe-Coded App Is Working. Now Someone Has to Support It.

A lot of small applications are getting built right now. Someone has a frustrating, repetitive problem, perhaps they need to clean up a report, move information from one system to another, or give customers a simpler way to complete a task. They use AI, a low-code tool, or just write a little code, and in a surprisingly short amount of time they have something useful. Then people start using it every day.

That is a huge win! The application proved that there is a real problem worth solving, which is often the hardest thing to figure out before building a larger project. The trouble is that once people depend on it, it has quietly stopped being just a quick experiment, even if it is still deployed like one.

Maybe it started as an internal tool that only a few people used, but now it is how a team gets a report out every week. Maybe it is a customer-facing feature that got enough use to become part of the product. Either way, when it stops working, someone notices pretty quickly, and the business usually has to work around it until it is fixed.

The app works until it doesn’t

This is a familiar situation. One person builds something useful and they know all the details: where it runs, how to deploy it, which API key it needs, and what to do when it gets weird input. Nobody else really has to think about it because the app has worked so far, and there are always other things to work on.

Then a dependency updates, an integration changes, or a user does something the original builder did not expect. The app might start throwing an error, or it might do something worse and quietly give the wrong answer. The person who built it could be on vacation, busy with a different project, or no longer at the company. Now a tool that people rely on has no clear owner and no obvious way for someone else to figure out what went wrong.

The original builder did not do anything wrong. Getting a useful version into people’s hands quickly is usually the right move, especially when nobody knows yet whether the idea will be valuable. However, proving that an idea works and operating an application that other people depend on are two different things, and they require a different level of support.

The small things are usually the big things

Most teams do not decide that error handling, monitoring, or security reviews are unimportant. They simply have not needed them yet, or they have been focused on getting the useful part of the application in front of people. When five people use a tool, it is easy to hear about a problem and fix it directly. When fifty people use it, or when customers use it outside of business hours, those shortcuts start to become real problems.

For example, what happens when an integration fails halfway through a process? If the app has already updated one system but has not updated the next system, can someone tell what happened and safely retry it, or do they have to start manually checking records to figure out what needs to be fixed? There may not be one right answer, but it is worth thinking through before the first time it fails in a way that affects the business.

Some other common things we see are:

  • An error happens, but the user gets an unhelpful message and there is no log that explains what actually failed.
  • Nobody knows whether the application is healthy until someone says it is broken in Slack.
  • Deploying a change means following a series of manual steps that live in one person’s head.
  • API keys and other credentials are stored wherever was convenient when the application was first built.
  • The application has its own username and password, even though everyone already signs in through the company’s identity provider.
  • It handles company or customer information, but nobody has taken the time to review who can see it, where the information goes, or how long it is kept.
  • No one besides the original builder knows how the pieces fit together or how to get the application back up after a problem.

None of these things are especially exciting or sexy to build, but they are the things that make a useful application either dependable or stressful to rely on. They are also usually much easier to address while the person who built the app is still around and the application is otherwise working well.

It does not mean starting over

The answer is not to take a working application away from the people using it and disappear for six months to rewrite it. Usually the application already has the most important thing: a real use case, people who can explain what matters, and an understanding of where it actually helps the business. Starting from that point is much better than starting from a blank page and guessing.

A better approach is to look at what is there, understand how it is being used, fix the biggest risks first, and add the support the application needs as it grows. The questions are fairly straightforward, but the answers tend to point to the work that matters most:

  • Where does it run, and how does a change get from code to users?
  • What happens when one of its services or integrations fails?
  • Can the team see errors, usage, and the health of the application without guessing?
  • Who has access to the application, its data, and its credentials?
  • Can it use the company’s existing login and access controls rather than adding another account for everyone to manage?
  • Could someone besides the original builder understand it, make a change, and respond to an issue?

Giving a useful app the support it needs

A production application does not need to be complicated, and not every small tool needs the same amount of process as a large customer-facing system. It does need a few basics that match the importance of the job it is doing.

A repeatable deployment process means changes can be reviewed, tested, and released in a predictable way instead of requiring a set of commands someone hopes they remember correctly. It also gives the team a reasonable way to roll back a bad change when one inevitably gets through.

Good error handling and visibility means useful errors for users, logs that explain what happened, and enough metrics, monitoring, and alerting to notice a problem before it turns into a long Slack thread. This is not about collecting every possible number; it is about being able to answer the basic question of whether the application is working and why it is not when it fails.

Security should fit how the company already works. That includes being deliberate about secrets, permissions, and data flows, as well as reviewing who should have access to the application. For an internal tool, using the company’s existing identity provider often avoids one more username and password for employees to manage, and makes it easier to remove access when somebody changes roles or leaves.

Finally, the application needs some documentation and shared ownership. A short overview of how the pieces fit together, a runbook for common problems, and more than one person who can work on it go a long way. The person who first built the application should not have to be the permanent support team just because they had the initiative to solve a problem.

If AI is part of the application, there are a few additional questions around testing prompt or model changes, handling unusual input, and deciding when a person should review an output. Those are important questions, but they sit alongside the same operational basics that every useful application needs.

Make the app more dependable while it is going well

The best time to make an application more supportable is when it is working and people are getting value from it. There is less pressure, the original builder can explain why the application works the way it does, and the team can make improvements without disrupting the workflow it supports.

This is the type of work Setfive can help with: understanding the application that exists today, stabilizing the areas most likely to cause trouble, reviewing security and access, putting appropriate infrastructure and monitoring in place, and making sure the business is not dependent on one person. The goal is not to turn every small application into a huge project. It is to make sure the useful thing stays useful as more people start relying on it.

Symfony2 and Impersonating Users, a Heads Up

Recently I was working on a project in which it admins were able to impersonate other users. It’s a fairly easy task to add to Symfony2, merely adding a switch_user reference to your firewall can make it possible, consult the Symfony docs for more on that. One thing I noticed was that every now and then when testing I would get weird errors after switching between multiple users, however it didn’t always happen. After some digging around, it turns out when you switch user it does not clear that sessions attributes, ie if you set attribute ‘hello’ to value ‘world’ it would persist after you’ve impersonated another user. This caused a few issues as on this application we used the session to store a few things like which set of database connections you currently use.

After looking at the SecurityBundle configuration setup it was clear that there wasn’t any options to have it clear all session attributes on switch user. At this point it was clear I needed to use an event listener as the firewall dispatched the SwitchUserEvent when a user successfully switched user. Below is an excerpt from my services.yml

services:
    my.login_listener:
        class: Setfive\DemoBundle\Listener\LoginListener
        tags:
            - { name: kernel.event_listener, event: security.switch_user, method: onSecuritySwitchUser }

This makes it so that it will call the following code on a successful impersonation of a user:

<?php
namespace Setfive\DemoBundle\Listener;

use Symfony\Component\Security\Http\Event\InteractiveLoginEvent;
use Symfony\Component\Security\Http\Event\SwitchUserEvent;

class LoginListener
{
  
    /**
     * Fired on switch user, you can remove attributes or whatever you want here.
     * @param SwitchUserEvent $event
     */
    public function onSecuritySwitchUser(SwitchUserEvent $event)
    {
        $session = $event->getRequest()->getSession();
        $session->remove('partThatShouldNotCarryOver');
        
    }
}

It’s as simple as that, you can get the actual user by calling $event->getTargetUser(). Long story short, the session can have some tainted values when using switch user as all attributes are not cleared.

Security questions, re-imagined

Earlier today we were discussing implementing “security questions” for a client of ours. The client felt that we should implement security questions so that users would have to answers one or more questions before taking certain actions on the site.

For those who aren’t familiar with the concept, some applications will ask users “security questions” at certain touchpoints in the application. The questions have been previously answered by the user and usually ask somewhat personal information like “what street did you grow up on?”, “what is the name of your favorite pet?”, “what was your high school’s mascot?”

As several security researchers have pointed out, the answers to these types of questions can be easily derived from a mix of a user’s social profiles and some social engineering. One of the most famous examples of this was the compromise of Sarah Palin’s email account during the lead up to the 2008 presidential campaign.

At the gym earlier, I started wondering about this problem and stumbled across what might be the basis of a novel solution.

The issue with the current solution is that the lexicon of questions asked are always pieces of personal information that users typically will share with the world. The obvious solution would be asking extremely personal questions like “who was your first kiss?”, “have you ever stolen something”, and so on. Unfortunately, these will undoubtedly make users uncomfortable and force the application to store extremely sensitive information.

What we’re really looking for is innocuous personal questions that users will not typically broadcast via social networks and also difficult to social engineer. With this in mind, my solution would be to ask questions that users don’t normally think about but when taken together, are identifiable enough to prove that a user is in fact genuine.

Here’s a few I thought of:

  • Do you signal a “3” with your three index fingers or with your thumb and two index fingers? (For those who haven’t seen it, this is discussed at length in The Inglorious Bastards)
  • Do you tie your shoes with “bunny ears” or with a loop?
  • What knot do you use to tie your necktie?
  • What type of seafood are you allergic to?
  • What brand of refrigerator do you currently own?

Obviously, some of these are multiple choice questions which makes a probabilistic attack easier but by using a combination of multiple choice and open ended I think you could end up with a pretty strong solution.

Anyway, I’d love to hear any feedback and other good questions if anyone comes up with them.