Bridging the Analogy to Reality
Tom’s story might seem like just a cautionary tale for construction, but the lessons extend far beyond bricks and mortar. In software development, I’ve seen firsthand how these same shortcuts manifest—with consequences that are just as alarming. Let me share an example from a project I reviewed to illustrate this point.
The Initial Review: Problems Uncovered
So, what was the project that I came across with these issues? To preserve confidentiality, I’ve adjusted the context a little, but the problems I’m about to describe remain true to the singular codebase.
When I was first brought onto this project, I wasn’t expecting a déjà vu moment—but that’s exactly what it felt like. This was the same project where I previously uncovered glaring authentication issues, before I had access to the source code. Accessing the codebase was like stepping into an eerily familiar construction site—one where cracks I had only glimpsed before now stood out plainly, impossible to ignore.
Spending just 45 minutes navigating the repository using a basic text tool—not even an IDE—was enough to peel back layers of systemic negligence. The flaws were hinted at before, but now laid bare in alarming detail. These weren’t isolated oversights, but rather patterns repeated with disconcerting consistency. To make sense of the scope, I categorised the issues into three critical areas: Legal, Security, and Quality.
Legal Concerns
- Copy-and-Paste Authentication Code:
- Issue: This code was taken directly from an online blog without any license for reuse.
- Implication: The unlicensed use of third-party code exposes the client to potential copyright infringement. If discovered, the client could face legal action, tarnishing their reputation.
- Embedded Client Data from Other Projects:
- Issue: The source code contained remnants of the contractor’s work for other clients, including sensitive documents, logos, credentials, and database schemas.
- Implication: This created a legal nightmare, breaching intellectual property laws and risking exposure of personally identifiable information (PII). It also highlighted an alarming lack of professionalism and confidentiality.
- Copy-and-Paste Email Code:
- Issue: Another blog-sourced snippet was used for email functionality, with no license for reuse.
- Implication: Apart from intellectual property concerns, this code contained hard-coded email addresses that was BCCd on specific emails. This may have violated data privacy regulations.
Security Concerns
- Hard-Coded Super Admin Credentials:
- Issue: A well-known username and password were hardcoded into the system and seeded during every startup. This account had unrestricted permissions. These credentials were the ones copied in from the blog.
- Implication: This vulnerability allowed anyone with access to the source code to gain total control over the platform. It undermined the core security of the application. Or, if a malicious actor was to try the well-known combination, they likely would have gained access by brute force.
- Lack of Input Validation:
- Issue: The application accepted any input, including invalid or malicious data, without validation. File uploads, for example, accepted any type of file type and size without restriction.
- Implication: This left the system vulnerable to injection attacks or malicious uploads, potentially compromising the entire platform.
- SMTP Relay Vulnerabilities:
- Issue: The contractor set up an SMTP relay on the client’s domain controller, using an outdated and vulnerable package.
- Implication: This posed a significant risk of exploitation, potentially allowing attackers to send spam or malware using the client’s domain.
- Accessible Wet Signatures:
- Issue: Signature glyphs for senior managers were stored in predictably named files and accessible without authentication.
- Implication: Anyone who guessed the file paths could misuse these assets, damaging the client’s credibility and trustworthiness, or having the ability to sign personal documents in the names of the impacted personnel.
- Unsecured Logging Practices:
- Issue: With no logging in place, there was no way to track user actions or system events. Even the occasional logs used hardcoded
Console.Writelinestatements instead of a logging framework. - Implication: This created a blind spot for security breaches, making it impossible to trace unauthorised access or debug problems effectively.
- Issue: With no logging in place, there was no way to track user actions or system events. Even the occasional logs used hardcoded
Quality Concerns
- Disjointed Development Styles:
- Issue: The codebase exhibited inconsistent coding styles, suggesting that multiple developers had contributed, despite the contractor claiming it was their solo work. However, it was also clear that a consistent style was not applied to the copy-and-pasted code, let alone a review of the incoming code.
- Implication: These inconsistencies created confusion for new developers, slowing down onboarding and increasing the likelihood of errors during updates.
- Generated Code Modified by Hand:
- Issue: Code generated by Entity Framework was manually altered, introducing inconsistencies and making automated updates impossible.
- Implication: The mix of raw SQL, reverse engineering, and manual edits made maintenance unpredictable and error-prone.
- Magic Numbers and Strings:
- Issue: The code was littered with unexplained constants and “magic” values.
- Implication: This lack of context made the code difficult to understand, increasing the risk of errors when changes were needed.
- No Documentation or Unit Tests:
- Issue: There was no documentation to explain the functionality, and no unit tests to verify code correctness.
- Implication: Every change introduced a high risk of regressions. Future debugging will be a time-consuming process of trial and error, compounding development costs, and requiring the client to be repeatably testing the same things that they have in the past, adding no real value.
- Dependency Injection and Abstractions Missing:
- Issue: Common components like email, file storage, and data access weren’t abstracted with interfaces or dependency injection.
- Implication: This created tightly coupled systems, making it harder to extend or refactor the code over time without introducing unintended issues.
- Low Code Hygiene:
- Issue: Classes and files had placeholder names like “do_not_use” and “old_version,” reflecting a rushed and careless development process.
- Implication: This uncleanliness complicated the codebase, making navigation and understanding a significant challenge for new developers. Some of the “do_not_use” was only subtly different with no explanation as to why it did not work, or should not be used.
Security and Quality Concerns
- Parameter Checking:
- Issue: Methods often included parameters like
string? nameOfString, and while there was a check for null values, whitespace (e.g., spaces, tabs, or newlines) was not handled. This resulted in unintended execution and inconsistent outcomes. - Security Implication: The lack of robust validation left the system vulnerable to unexpected behavior or execution paths, which could be exploited.
- Quality Implication: This led to confusing and inconsistent results in workflows, making debugging and ensuring correctness much more challenging.
- Issue: Methods often included parameters like
- Testing Deficiencies:
- Issue: The application had no unit tests, making it impossible to validate whether existing functionality worked as intended or to catch regressions when changes were made.
- Security Implication: Sections of the code responsible for processing sensitive information lacked safeguards to ensure accurate computation. Any refactor could inadvertently corrupt downstream processes, impacting data integrity.
- Quality Implication: Without tests to verify outputs, developers had no reliable way to confirm that system updates wouldn’t introduce bugs. The absence of this safety net created inefficiencies and eroded confidence in the application’s stability.
The findings from this software project painted a troubling picture of systemic negligence and oversight. In just 45 minutes of exploring the codebase, the depth and scale of the issues became plain to see. These included unlicensed copy-and-paste code riddled with security flaws, no input validation or testing, and hardcoded credentials that exposed the system to significant vulnerabilities. On top of this, the absence of logging, poor code hygiene, and inconsistent development practices rendered the system nearly impossible to maintain or expand.
Each discovery echoed the shortcomings in Tom the Builder’s work—quick fixes and cost-saving measures that ultimately led to long-term problems. Just as asbestos and unsealed water closets in the house posed unseen risks until too late, these software defects had quietly accumulated, jeopardising the client’s goals for the project. This review underlined one key takeaway: cutting corners might save time in the short term, but the consequences can be catastrophic.
Technical Pitfalls – Authentication, Logging, Input Validation, and More
Peeling back the layers of this project revealed deep and systemic issues that undermined its functionality, security, and maintainability. These technical pitfalls weren’t isolated hiccups—they were fundamental flaws that rendered the system unfit for purpose. Here’s a closer look at some of the most pressing concerns:
Authentication Woes
The authentication system exemplified a cocktail of legal, security, and quality failures.
- Copy-and-Paste Code: The core authentication code was lifted straight from a public blog, unlicensed and unfit for purpose.
- Hardcoded Super Admin Credentials: To make matters worse, it included hardcoded credentials, granting anyone with access to the source code full control over the application. This wasn’t just a misstep—it was an open door to exploitation.
These issues were strikingly similar to Tom’s use of asbestos—a low-cost shortcut with hidden dangers that any builder should know about. Just as removing asbestos is hazardous and expensive, replacing or securing an ill-conceived authentication system is both disruptive and costly.
Logging Omissions
The lack of proper logging mechanisms was another glaring issue.
- Unconfigured Logging Framework: The system lacked any proper logging. Errors and user actions weren’t recorded, leaving other developers and administrators blind to critical events.
- Ad-Hoc Console Statements: In a handful of places, logging consisted of rudimentary
Console.Writelinestatements—another symptom of carelessness.
This is akin to Tom skipping the sealant on water closets and laundry areas—allowing leaks and mold to grow unchecked. Proper logging, like waterproofing, is essential to ensure the integrity of a system over time.
Input Validation Failures
Input validation was non-existent, leaving the application vulnerable and its users frustrated.
- Unrestricted File Uploads: Files of any type could be uploaded, including malicious or improperly formatted ones.
- Frequent Database Errors: End users often encountered database errors due to unvalidated inputs, leading to lost progress and poor user experience.
Much like Tom’s unsealed windows and doors, this lack of input validation allowed undesirable elements—be it bugs, vulnerabilities, or user frustration—to seep into the system.
Inconsistent Design and Testing
Without a coherent structure or safeguards, the codebase was fragile and difficult to evolve.
- No Unit Tests or Documentation: The absence of unit tests and meaningful documentation left the system prone to regressions and made onboarding new developers a daunting challenge.
- Hand-Modified Generated Code: Entity Framework code was manually altered, creating inconsistencies and compounding maintenance difficulties.
This resembled Tom’s flimsy wall studs—lacking the strength to support the long-term demands of the project and complicating efforts to add or fix anything later.
These technical pitfalls don’t just highlight poor practices—they reveal a disregard for the essential principles of software development. They’re a testament to the dangers of cutting corners, whether in construction or in code.
Highlighting the Discovery Process
The process of uncovering the issues in this project wasn’t reliant on specialised tools or automated analysis—it was entirely manual. Equipped only with a basic text tool (limited syntax highlighting) and no IDE, I approached the codebase as if navigating an unfamiliar but organised landscape, guided by the client’s request for an SBOM (Software Bill of Materials). This request set the tone for the review: I needed to identify critical components, dependencies, and risks present within the system.
To achieve this, I leveraged an intuitive yet methodical approach:
- Folder and File Structure: I began by scanning the folder names and file names, which, thanks to their organisation, allowed me to quickly locate areas likely tied to critical functionality. Patterns in naming conventions hinted at where deeper issues might reside.
- Execution Path Analysis: By tracing the presumed execution flow of the application, I identified key files that appeared central to vital operations such as authentication, the lack of logging, and input validation.
- NuGet Package Review: I conducted a quick review of the NuGet packages included in the project, identifying outdated libraries and dependencies with known vulnerabilities. This step highlighted potential security risks and the lack of attention to maintaining up-to-date, reliable components.
- Targeted Deep Dives: With potential problem areas identified, I thoroughly reviewed the content of key files to assess how they contributed to functionality—or, in many cases, undermined it. This included a detailed, line-by-line analysis of the
Program.csandStartup.csfiles, which revealed further issues with configuration, initialisation, and security setup.
The code’s structured organisation made navigation straightforward, enabling me to focus quickly on areas of interest. For instance, I found the copy-pasted authentication code almost immediately, followed by the hardcoded credentials that were seeded into the database on every application startup. I also identified unique snippets of code and cross-referenced them online to discover their full, original versions. Similarly, the absence of input validation and remnants from the contractor’s other projects stood out clearly as I delved deeper into the folder structure.
This manual but efficient method revealed systemic flaws with surprising speed. Even the review of Program.cs and Startup.cs exposed a lack of proper initialisation and reliance on unsafe practices, further reinforcing the broader issues. It was a stark reminder that even in a well-organised codebase, a lack of oversight, accountability, and best practices can leave major vulnerabilities and challenges unaddressed. The review process underscored not just the breadth of the issues, but also the pressing need for remediation.
Lessons Learned: Bridging the Analogy to Reality
This project reinforced a critical lesson: whether you’re building a house or a software system, cutting corners may seem like an efficient solution in the short term, but it almost always results in long-term pain. The issues uncovered in this codebase—the unlicensed copy-paste code, hardcoded credentials, missing logging, and lack of input validation—are strikingly similar to the mistakes made by Tom the Builder in the analogy from Post 1. Just as Tom prioritised speed and cost over quality and safety, this project’s developer sacrificed best practices and long-term stability in favour of quick delivery.
The second blog in this series delved into these technical pitfalls, uncovering the ripple effects of these shortcuts. From legal risks like intellectual property violations to fundamental security flaws and quality deficits, the issues weren’t just surface-level—they were deeply ingrained and systemic. These problems didn’t merely jeopardise the immediate functionality of the system; they compromised its ability to evolve, adapt, and support the client’s future needs.
If there’s one overarching takeaway, it’s this: attention to detail and a commitment to quality aren’t optional—they’re foundational. Without them, you end up with a system riddled with “asbestos-like” defects, unsealed “water closets” of vulnerabilities, and “drafty windows” of poor validation and logging. Fixing these issues after the fact, as both the family in the analogy and the client in this project learned, is exponentially more difficult, costly, and time-consuming.
Looking ahead, the next post in this series will explore how to break this cycle by learning from these mistakes. It will outline practical strategies for avoiding the pitfalls of cutting corners and creating systems—be they houses or software—that are built to last.
Post 1 – The Asbestos home builder: A tale of cutting corners
Post 2 – Non-technical – The project behind the analogy
Part 3 – Strategies for Improvement
After the initial story
After this initial story was shared (not when it was written) further analysis revealed critical flaws in how files were downloaded, each making unauthorised access trivial:
Files Stored Directly in wwwroot/uploads
- Files uploaded were placed into wwwroot which is unadvisable.
- IIS treated these files as static content and served them without routing through any controller logic.
Unrestricted Public Access
- Files were reachable via predictable URLs:
https://<domain>/uploads/<filename>.<extension>. - No access checks, authorisation, or token-based controls were applied.
- This meant:
- Anyone who knew or could guess a filename had full access.
- Malicious actors could serve executable scripts, assets, or phishing pages directly from the domain.
No Access Controls on /download/<int ID>
- The endpoint was publicly accessible.
- No authentication or authorisation was enforced.
- Any user could retrieve files using a simple HTTP GET request.
Predictable Identifier Scheme
- File identifiers used incrementing integers (e.g. /download/101, /download/102).
- Attackers could guess IDs and mass-download files.
- No rate limiting or anti-enumeration mechanisms were present.
Missing Audit and Access Logs
- File access events were not logged.
- No metadata (user ID, timestamp, source IP) was captured.
- This made unauthorized downloads:
- Invisible to maintainers.
- Impossible to trace after the fact.
Security Implications
- Web shells could be uploaded and executed, bypassing any business logic protections.
- Sensitive documents were exposed with no traceable download mechanism.
- No isolation between static content and user uploads, breaking secure design principles.
Some of this was able to be resolved as a workaround without modifying the source code by adding to the IIS web.config other parts required changes to the source code. This is a work around, and has the potential of breaking the application.
<system.webServer>
<security>
<requestFiltering>
<fileExtensions>
<add fileExtension=".pdf" allowed="false" />
<!-- Add more as needed -->
</fileExtensions>
<hiddenSegments>
<add segment="wwwroot" />
</hiddenSegments>
</requestFiltering>
</security>
</system.webServer>XMLThe remediations to this is to refactor where files are stored after they are uploaded to not be in the wwwroot, and controller has the [Authorize] attribute, the file ID is updated to be non-sequential and random.
