Skip to main content
A hand holding a red pen ticks items on a clipboard checklist beside a closed laptop, with a filing cabinet and a small network switch in the background of a small office
IT Strategy

Secure Custom Software: What a Well-Run Project Looks Like

Where it should run, how tests and change control keep it safe for years, and the questions to ask any developer, in-house or vendor, before the first line of code.

By William Bradshaw | November 5, 2026 | 11 min read

Most small organizations run more custom software than they think: the website intake form, the script that copies time entries into payroll, the portal where contractors upload certificates, the macro that builds the board report. Each was written for you by someone, and each holds data and access that matter.

This guide is for the owner, office manager, fire chief or finance director who commissions that work but does not write code. It explains what a secure, well-run project looks like whether the software runs in the cloud, on your own servers, or across both, so you can recognize good practice and ask the right questions of any developer.

If your goal is to automate a repetitive back-office task, start with our companion guide to automating repetitive back-office work, with or without AI. This one covers how to build and run that automation, or any custom tool, so it stays safe for years.

Why Custom Software Needs the Same Discipline as Infrastructure

Nobody would let a contractor reconfigure the firewall with no record of what changed. Custom software deserves the same care, because the risk lives in two places:

  • The data it touches. A billing integration reads customer names, amounts and sometimes card or bank details. A township records portal handles public records with retention rules. A clinic scheduling tool handles protected health information. The rules that apply to the data apply to the software that moves it.
  • The access it holds. Glue code usually runs under a service account, often created in a hurry with administrator rights "to make it work." It becomes a standing key to your systems that nobody reviews or remembers to disable.

Custom software also outlives its author. The script a helpful employee wrote in 2021 is still running after they have left. The practices below let the next person understand it, change it safely, and prove to an auditor or insurer what it does.

Choosing Where It Runs: Cloud, On-Premises or Hybrid

Decide where the software lives before anyone writes it, because the answer shapes the cost, the security model and how hard it is to leave later.

Cloud-native

The software runs on a provider's managed services: hosted databases, containers, or serverless functions that run only when called. You do not patch servers or replace disks. The trade is a monthly bill that grows with use, data on someone else's hardware, and design choices that can tie you to one provider.

On-premises

The software runs on hardware you own, usually as virtual machines on a platform such as Proxmox. You control where the data lives, which matters when a contract, the Health Insurance Portability and Accountability Act (HIPAA) business associate terms or the Criminal Justice Information Services (CJIS) Security Policy constrain who can reach it, or when a system must work with no internet connection at all. The trade is that you own the patching, the backups and the hardware lifecycle.

Hybrid

The sensitive data stays on site and a thin front end, such as a public request form, runs in the cloud and passes submissions inward over a secured connection. Hybrid is common for public entities because it keeps records local while giving residents a reliable web page.

Question Cloud-native On-premises Hybrid
Data sensitivityFine for most business data with encryption and a signed agreementStrongest control over location and accessSensitive data stays local, public parts go out
Compliance constraintsCheck the provider's contract terms for HIPAA, CJIS or Payment Card Industry Data Security Standard (PCI DSS) scopeYou carry every control yourselfScope can be narrowed to the local part
Cost profileLow to start, monthly, grows with useUp-front hardware, then flat and predictableSome of each
Staff skills neededProvider console and identity settingsServer, backup and network administrationBoth, plus the connection between them
Uptime needsHigh availability is a setting, at a priceAs good as your power, hardware and internetPublic front end stays up if the office is down
Exit and lock-inEasy to enter, harder to leave if built on proprietary servicesEasiest to move if built on open-source partsDepends on which half holds the logic

On lock-in: building on open standards and open-source components (a standard database, containers, plain configuration files) keeps the option to move. That does not mean avoiding managed services; it means writing down which parts would need rewriting if prices or terms change. Our articles on cloud repatriation and multi-cloud strategy go deeper on the cost side.

Test-Driven Development, in Plain Terms

Test-driven development (TDD) means the developer writes a small automated test that describes "done" before writing the code that does the work. The test fails at first, because the feature does not exist yet. The developer then writes just enough code to make it pass. Three habits come with it:

  • Every bug gets a test first. When something breaks, the developer writes a test that reproduces the failure, watches it fail, then fixes the code. That bug can never quietly return.
  • Tests run automatically on every change. A continuous integration (CI) service runs the whole suite each time code is pushed, on a clean machine, without anyone remembering to do it.
  • Red blocks the merge. If any test fails, the change cannot be merged into the main version. Nobody has to argue about it.

Here is what a test looks like for a simple late-fee rule. You do not need to read code to follow it:

test('no late fee on day 30', () => {
  expect(lateFee({ amount: 200, daysOverdue: 30 })).toBe(0);
});

test('5 percent late fee from day 31', () => {
  expect(lateFee({ amount: 200, daysOverdue: 31 })).toBe(10);
});

That business rule, written down before the code, is now checked on every change for the life of the software. If someone edits the fee calculation next year and gets the boundary wrong, the test goes red before a customer sees it.

Why this matters to someone who never reads the code: fewer surprises after an update, the ability to change the software safely years later with a different developer, and a dated record that each change was tested. That record is exactly the evidence an auditor asks for. It is how we build our own website, as described on our development page.

Change Management That Auditors Recognize

Done well, change management is mostly automatic: the tools record the trail as a side effect of the work. A healthy cycle for every change looks like this:

  1. A tracked issue with an estimate. The request is written down: what, why, who asked, and roughly how long it should take.
  2. Work on a branch. The developer works on a separate copy of the code, so the live version is never edited directly.
  3. A merge request with review. The finished change is proposed back to the main version, the automated tests run, and a second person reviews it.
  4. A preview or staging deploy that a human checks. The change runs in a copy of the real environment, and someone who knows the business confirms it does what was asked.
  5. A release tag and changelog. The approved version gets a number and a plain-language note of what changed.
  6. One-step rollback. If the release misbehaves, the previous tagged version can be restored in one action, and that action has been practiced.
  7. The issue closed with actual time logged. Estimates become more accurate, and the cost of each change is visible.

How that maps to the frameworks our clients answer to:

Framework What it expects of software changes
Sarbanes-Oxley Act (SOX) IT general controls (ITGC)For systems that feed the financial statements, auditors sample changes and look for a request, testing evidence and approval before production, with the developer and the person deploying kept separate. See our SOX ITGC guide.
PCI DSS v4.0.1, Requirement 6.5.1Production changes follow documented procedures covering the reason and description, the security impact, approval by authorized parties, testing, and a way to return to a secure state if the change fails.
CJIS Security Policy (v6.0 and later)Organized on National Institute of Standards and Technology (NIST) SP 800-53 control families, including configuration management with configuration change control and impact analysis. Contractor access to criminal justice information is brought into scope through the CJIS Security Addendum.
Ohio Revised Code (ORC) 9.64 (Ohio political subdivisions)Does not name change control. It requires a cybersecurity program consistent with generally accepted best practices such as the NIST Cybersecurity Framework and Center for Internet Security (CIS) guidance, and both cover configuration management and secure development. A documented change process is a reasonable way to show that. See our ORC 9.64 readiness guide.
ORC Chapter 1354 (Ohio businesses)A voluntary safe harbor for a written program that reasonably conforms to a recognized framework. Change records are part of showing the program was followed, not just written.
HIPAA Security RulePrescribes no specific change process, but requires risk analysis, access and audit controls, and periodic evaluation, including after environmental or operational changes that affect the security of electronic protected health information.

Our compliance mapping guide shows how one set of controls can answer several of these frameworks at once. Run one good process that produces evidence for all of them, not one per regulation.

Security Built In, Not Bolted On

These controls are cheap on day one and expensive after an incident.

  • Least-privilege access. Each piece of software gets its own service account with only the permissions it needs: read-only where it only reads, one database instead of the whole server. People get named accounts with multi-factor authentication (MFA), never a shared login.
  • Secrets kept out of the code. Passwords, application programming interface (API) keys and connection strings live in environment settings or a secret store, never in the source files. Assume anything committed to a repository is readable by everyone who will ever see it.
  • Dependency and supply-chain hygiene. Modern software is mostly other people's packages. Pin exact versions in a lockfile, so every build installs the same thing. Wait about a week before adopting a newly published version: in one review of ten prominent supply-chain attacks, eight of the poisoned releases were found and pulled in less than a week. A wait is not a guarantee, so keep the other checks too. Block package install scripts that do not need to run. Run a vulnerability audit in CI so a known-vulnerable package fails the build.
  • Exposure checks. Internal files (configuration, documentation, test data) must never be publicly served. An automated test that requests those paths on the live site and expects "not found" catches a mistake before an attacker does.
  • Private repositories. Source code and its history belong in a private repository that your organization controls, with access reviewed like any other system.
  • Logging and an audit trail. The software should record who did what and when, in a place the application itself cannot erase. For public entities, check how long those logs and any records the software creates must be kept under your records commission's retention schedule (ORC 149.38 for counties, 149.39 for municipalities and 149.42 for townships; other public bodies have their own sections in Chapter 149).
  • Backups and restore tests. Back up the data and the configuration, and restore them on a schedule to prove it works. Our offsite backup guide covers the restore record insurers ask for.

Cyber-insurance questionnaires ask about MFA, backups, patching and unsupported software. Custom code is software you must patch, so keep it on the same schedule as everything else (see our patch management guide), and scan what it exposes like any other system (see open-source versus commercial scanners).

Reusable Automation: Each Project Gets Cheaper and Safer

The first well-run project costs the most, because the scaffolding has to be built. A good developer builds it so it carries forward:

  • CI pipeline templates that run lint checks, tests, the vulnerability audit and the exposure checks, copied into the next project on day one.
  • Infrastructure as code. Servers, firewall rules and deployment steps are described in files (for example, Ansible roles and templates) rather than clicked together by hand, so the environment can be rebuilt identically and reviewed like code.
  • Shared test suites and release scripts. The checks that guard one project (no secrets committed, no internal paths exposed, version numbers in agreement) become a library every later project inherits.
  • Documentation someone else can run. A short runbook for deploying, backing up, restoring and rolling back that a competent stranger could follow. This is how a small organization gets mature practice without a large team.

Right-Sizing: Do Not Gold-Plate a One-Page Form

Every practice above scales down. Match the process to what the software touches.

Practice 5-person office, low-risk tool Regulated business or city department
Repository and historyPrivate repository you ownSame, plus a mirrored backup and access reviews
TestsTests for the business rules and every bug fixedFull suite in CI that blocks merges
ReviewOwner checks a preview before releaseSecond-person code review, separate deployer
Change recordsAn issue per change and a changelogIssue, approval, test evidence and release tag per change
RuntimeManaged hosting is usually fineChosen against data residency, retention and contract terms

Questions to Ask Any Developer or Vendor Before You Start

  1. Whose account will the source code live in, and will we have full access to it from the first day?
  2. Where will it run, and why is that the right place for our data and our staff?
  3. How do you write tests, and will they run automatically on every change?
  4. What happens when a bug is found? Do you add a test that reproduces it?
  5. How are changes requested, reviewed and approved, and who signs off before release?
  6. Can we see a change in a preview or staging copy before it goes live?
  7. How do we roll back a bad release, and how long does it take?
  8. What accounts and permissions will the software need, and why each one?
  9. Where will passwords and keys be stored, and who can see them?
  10. How do you choose, pin and audit third-party packages?
  11. What does the software log, and how long are logs and records kept?
  12. If you are unavailable next year, what would another developer need to take over?

What You Should Receive at Handoff

  • Source code in a repository your organization owns, including its full history, not a zip file.
  • The automated tests and the CI pipeline that runs them, passing.
  • A runbook covering deployment, backup, restore, rollback and who to call.
  • A credentials inventory: every service account, key and integration, what it can do, and where its secret is stored (the inventory lists them; it does not contain the secrets).
  • The change history: issues, merge requests, release tags and the changelog.

Frequently Asked Questions

Does a small internal tool really need automated tests and change control?

It needs the version that fits its risk. A one-page form that stores nothing sensitive needs a repository you own, a handful of tests and a written way to roll back. A tool that touches payroll, patient records, card data or criminal justice information needs the full process: tracked issues, reviewed changes, a staging check and a release record.

Should our custom software run in the cloud or on our own servers?

Decide from the data and the people, not the trend. Cloud services suit public-facing tools and teams without server skills. On-premises suits sensitive data with residency or contract constraints and organizations that already run their own virtualization. Hybrid, with data kept on site and a thin front end in the cloud, is common and often the best fit for public entities.

Planning a Custom Tool or Inheriting One?

Bullium helps small businesses and Ohio public entities scope, build and review custom software with the tests, change records and runbooks described here, or take stock of a tool you already depend on. We start with a conversation about what the software touches and who relies on it. No commitment to engage further.