← Back to list

How Do I Know If My Codebase Is Safe?

A codebase can pass CI, have 80% test coverage, produce no critical SAST findings, and still be unsafe.

Praveen · 2026-08-11 16:33 · 0 claps · 15.5 min read
#codebase-security #code #clean-code #the-code-registry #software-security
Open on Medium ↗
Wiki topics: RAG · RAG & Retrieval

How Do I Know If My Codebase Is Safe?

A codebase can pass CI, have 80% test coverage, produce no critical SAST findings, and still be unsafe.

That sounds counterintuitive until you look beyond individual functions.

A production codebase is a system of source code, dependencies, configuration, infrastructure, build pipelines, repositories, credentials, APIs, data flows, deployment processes, and human decisions. Increasingly, it also contains code generated or modified by AI coding assistants and autonomous coding agents.

So the better question is not:

“Does my code have vulnerabilities?”

It is:

“Do I have enough evidence to understand the security, architecture, dependency, quality, provenance, and operational risks in my codebase?”

That is the difference between code review and codebase assurance.

The Short Answer

A codebase is reasonably safe when its material risks are known, validated, prioritized, owned, and controlled.

A meaningful codebase safety assessment should examine at least six dimensions:

  1. Security
  2. Architecture
  3. Software supply chain
  4. Code quality and technical debt
  5. Governance and provenance
  6. Operational and AI-generated code risk

No single scanner, test suite, code review, or SBOM can prove that a codebase is safe.

The objective is not zero defects.

The objective is understood and controlled software risk.

What Does “Safe Codebase” Actually Mean?

A “safe” codebase does not mean bug-free code.

Software contains defects. Requirements change. Dependencies develop vulnerabilities. Architecture evolves. Engineers make trade-offs. AI coding tools introduce another source of generated code that must be validated.

Therefore, safety should be treated as a risk spectrum rather than a binary property.

A useful model is:

This matters because individual risks can interact.

For example, an outdated dependency is one problem.

An outdated dependency inside a business-critical service with no clear owner, poor test coverage, and tightly coupled architecture is a much larger problem.

The Engineering Principle

A useful way to think about software assurance is:

Finding a problem is not the same as understanding the problem.

And:

Understanding the problem is not the same as controlling the problem.

A mature engineering organization moves through:

Detect
↓
Understand
↓
Validate
↓
Prioritize
↓
Remediate
↓
Verify
↓
Monitor

NIST’s Secure Software Development Framework follows a similar lifecycle-oriented philosophy by integrating secure development practices into the software development lifecycle rather than treating security as a final-stage inspection.

How Do You Assess the Security of a Codebase?

The first layer is conventional application security.

You need to understand whether the application contains vulnerabilities that attackers could exploit.

But a useful security assessment goes beyond running a scanner.

1. Authentication

Review:

  • Password handling
  • Session management
  • Token validation
  • MFA implementation
  • Authentication bypass paths
  • Identity-provider integrations

2. Authorization

Ask:

  • Can users access resources they should not?
  • Are authorization checks centralized?
  • Are object-level permissions enforced?
  • Are administrative operations adequately protected?

3. Input and Output Handling

Look for:

  • SQL injection
  • Command injection
  • Cross-site scripting
  • Path traversal
  • Template injection
  • Unsafe deserialization
  • Improper validation

4. Secrets

Search for:

  • API keys
  • Database passwords
  • Private keys
  • Tokens
  • Connection strings
  • Credentials in configuration files

Secrets management should be treated as a lifecycle problem rather than simply a repository scanning problem.

5. Cryptography

Review:

  • Algorithm selection
  • Key storage
  • Random-number generation
  • Certificate validation
  • Password hashing
  • Encryption boundaries

6. Security Configuration

Examine:

  • Default credentials
  • Debug modes
  • Excessive permissions
  • CORS
  • TLS configuration
  • Logging
  • Error responses
  • Administrative interfaces

SAST Is Necessary, Not Sufficient

Static Application Security Testing can identify valuable patterns, but automated analysis has limitations.

A finding might be:

  • exploitable,
  • unreachable,
  • mitigated elsewhere,
  • incorrectly classified,
  • or architecturally significant in a way the scanner cannot understand.

Therefore:

SAST Finding
↓
Contextual Analysis
↓
Exploitability Assessment
↓
Business Impact
↓
Priority

Practical Example

Suppose a static-analysis tool identifies SQL injection in an internal API.

A developer may initially classify the issue as low priority because the API is not internet-facing.

Further analysis reveals that:

  • the API is accessible from another production service,
  • that service accepts externally controlled input,
  • the database account has excessive permissions.

The original finding was technically correct.

Its initial risk classification was not.

Key Principle

Security findings must be interpreted in application context.

That is why a codebase security assessment should combine automated analysis with architecture, dependency, runtime, and business context.

How Do You Know Whether Your Architecture Is Safe?

Security vulnerabilities are not the only way software can fail.

Architecture can create risk even when individual functions are secure.

Consider a system with:

At first glance, this might look reasonable.

But if every service directly accesses the same database, the system may have hidden coupling.

A schema modification made by one team could affect several unrelated services.

That is architecture risk.

Architecture Assessment Should Examine

  • Service boundaries
  • Data ownership
  • Coupling
  • Cohesion
  • Shared databases
  • External integrations
  • Authentication boundaries
  • Authorization boundaries
  • Failure propagation
  • Single points of failure
  • Retry behavior
  • Message queues
  • API dependencies
  • Configuration dependencies
  • Infrastructure dependencies
  • Architecture drift

Architecture Drift

Architecture rarely fails in one dramatic event.

It usually drifts.

Designed Architecture
        ↓
Feature Shortcut
        ↓
Shared Utility
        ↓
Direct Database Access
        ↓
Cross-Service Dependency
        ↓
Undocumented Coupling
        ↓
Architecture Drift

The system continues to work.

That is what makes the risk difficult to detect.

Practical Example

A team introduces a direct database query because creating a formal API would delay a release.

Six months later, three services depend on the same schema.

The original shortcut has become an architectural dependency.

Now changing that schema requires coordinating multiple teams.

The Engineering Question

Do not ask only:

“Does this architecture work?”

Ask:

“Can we safely change this architecture?”

That is a much stronger measure of software health.

How Do You Assess Dependency and Software Supply Chain Risk?

Modern applications are assembled from thousands of software components.

Your repository may contain code written by your organization, but the executable software may also include:

  • Open source packages
  • Transitive dependencies
  • Container images
  • Build plugins
  • GitHub Actions
  • Infrastructure modules
  • Package-manager artifacts
  • Cloud components
  • Third-party SDKs

This creates a software supply chain.

CNCF’s supply-chain security guidance covers security across source code, materials, build pipelines, artifacts, and deployment.

Start With an Inventory

An SBOM can answer:

“What components are inside this software?”

That is valuable.

But an SBOM does not answer every supply-chain question.

You also need to understand:

  • Where did the component come from?
  • Which version is being used?
  • Is it maintained?
  • Does it contain known vulnerabilities?
  • Is it actually reachable?
  • What license applies?
  • How was the final artifact built?
  • Can the build process be trusted?

SBOM vs Provenance

Think of them as different questions.

SLSA defines provenance as verifiable information describing where, when, and how software artifacts were produced.

Google’s Open Source Security Team has also emphasized build provenance and tamper-resistant build processes as mechanisms for improving software supply-chain integrity.

Practical Example

Imagine an application uses 300 open-source packages.

A dependency scanner identifies one package with a known vulnerability.

That does not automatically mean the application is exploitable.

You need to determine:

  1. Is the vulnerable package actually included in the production artifact?
  2. Is the vulnerable function reachable?
  3. Is the affected feature enabled?
  4. Is the package exposed to untrusted input?
  5. Is there a patched version?
  6. What applications use the same package?

The last question matters because dependency risk can be systemic.

The Supply Chain Principle

Software inventory tells you what you have. Software intelligence tells you what matters.

How Do You Measure Code Quality and Technical Debt?

Security teams tend to focus on vulnerabilities.

Engineering teams tend to focus on quality.

Executives often focus on delivery speed.

The real software-risk picture requires all three.

Useful Code Quality Signals

Consider:

  • Cyclomatic complexity
  • Code duplication
  • Code churn
  • Test coverage
  • Defect concentration
  • Dead code
  • Large modules
  • Long methods
  • Dependency complexity
  • Documentation gaps
  • Unsupported frameworks
  • Obsolete runtime versions
  • Maintainability

None of these metrics should be interpreted independently.

For example, high complexity in a stable, well-tested algorithm may be acceptable.

High complexity in a frequently modified payment component with poor test coverage is a very different situation.

Technical Debt as Risk

Technical debt becomes significant when it limits the organization’s ability to change software safely.

Examples:

Old Framework
      ↓
Limited Upgrade Options
      ↓
Security Patch Difficulty
      ↓
Higher Maintenance Cost
      ↓
Modernization Constraint

Or:

Undocumented Business Logic
          ↓
Key-Person Dependency
          ↓
Slow Changes
          ↓
Higher Defect Probability
          ↓
Operational Risk

Practical Example

A 15-year-old application may have relatively few known vulnerabilities.

But suppose:

  • only two engineers understand it,
  • business rules are undocumented,
  • tests are incomplete,
  • the framework is obsolete,
  • deployments are manual.

Calling the application “low risk” because its vulnerability count is low would be misleading.

Better Question

Instead of asking:

“How much technical debt do we have?”

ask:

“Which technical debt prevents us from making important changes safely?”

That produces a much more actionable engineering metric.

How Do You Know Who Owns Your Code?

Ownership is an underrated software-security control.

Imagine discovering a critical vulnerability in a shared library used by 40 applications.

You identify the vulnerable package.

Then someone asks:

“Who owns the applications?”

Nobody knows.

That is a governance failure.

Repository Governance Should Establish

  • Repository ownership
  • CODEOWNERS
  • Branch protection
  • Pull-request approval
  • Administrative access
  • Release permissions
  • Secrets access
  • CI/CD permissions
  • Service ownership
  • Dependency ownership
  • Incident responsibility

CNCF’s security best practices include repository security and security self-assessment as part of broader project-security practices.

Ownership Map

A mature software inventory should ideally produce something like:

Application
|
+ - Repository
|
+ - Business Owner
|
+ - Engineering Owner
|
+ - Security Owner
|
+ - Critical Dependencies
|
+ - Production Environment
|
+ - Deployment Pipeline

This allows security findings to be connected to accountable teams.

Practical Example

A vulnerability affects a shared authentication component.

Without ownership intelligence:

Security → ticket → team discovery → escalation → remediation

With ownership intelligence:

Finding → critical component → owning team → affected applications → remediation

That difference matters during incidents.

How Does AI-Generated Code Change Codebase Safety?

AI coding assistants are changing how software is produced.

Developers can use AI to generate:

  • Functions
  • APIs
  • Tests
  • SQL
  • Infrastructure code
  • Configuration
  • Documentation
  • Refactoring proposals
  • Security fixes

Tools such as GitHub Copilot have made this workflow increasingly normal.

But generated code is still code.

It needs engineering validation.

GitHub’s guidance for reviewing AI-generated code recommends checking functionality, context, quality, dependencies, AI-specific pitfalls, collaborative review, and automated checks.

Microsoft similarly recommends that developers understand and test AI-generated code rather than treating AI-generated output as automatically trustworthy.

What Can Go Wrong?

AI-generated code can introduce:

  • Incorrect assumptions
  • Hallucinated APIs
  • Insecure coding patterns
  • Outdated APIs
  • Unnecessary dependencies
  • Incorrect error handling
  • Weak tests
  • Incorrect business logic
  • Architecture inconsistencies
  • Misleading comments
  • Incomplete edge-case handling

The Generated-Test Problem

One particularly subtle issue is generated tests.

Imagine an AI agent generates:

def calculate_discount(price, customer_type):
…

It then generates tests for the function.

All tests pass.

But what if the business rule itself was misunderstood?

The tests prove that the implementation behaves consistently with the test assumptions.

They do not prove that the assumptions are correct.

This creates a dangerous possibility:

AI can generate both the implementation and the evidence used to validate the implementation.

Human domain validation remains important.

AI Provenance

As AI agents become more capable, enterprises will need to understand:

Developer
    ↓
AI Assistant / Agent
    ↓
Prompt / Context
    ↓
Generated Change
    ↓
Automated Tests
    ↓
Human Review
    ↓
Build
    ↓
Artifact
    ↓
Production

The important governance question becomes:

“Can we establish what changed, how it was generated, how it was validated, and who approved it?”

AI Does Not Automatically Mean Unsafe

AI-generated code should not be treated as inherently dangerous.

Nor should it be trusted automatically.

The correct approach is risk-based verification.

A trivial documentation change does not require the same scrutiny as an AI-generated modification to:

  • authentication,
  • cryptography,
  • payment logic,
  • access control,
  • infrastructure,
  • data migration,
  • authorization.

Practical Rule

The higher the potential impact of the generated change, the stronger the verification requirements should be.

The Enterprise Codebase Safety Framework

A practical framework is:

Discover → Understand → Assess → Validate → Govern → Monitor

1. Discover

Build an inventory of:

  • Repositories
  • Applications
  • Services
  • Languages
  • Frameworks
  • Dependencies
  • Infrastructure
  • Build systems
  • Owners

2. Understand

Map:

  • Architecture
  • Data flows
  • Dependencies
  • Business logic
  • Ownership
  • Trust boundaries
  • Deployment paths

3. Assess

Evaluate:

  • Security
  • Architecture
  • Dependencies
  • Technical debt
  • Code quality
  • Secrets
  • Provenance
  • Licensing
  • Compliance

4. Validate

Validate findings using:

  • Human review
  • Dynamic testing
  • Automated tests
  • Architecture analysis
  • Runtime evidence
  • Dependency reachability

5. Govern

Turn requirements into enforceable controls:

  • Branch protection
  • Required reviewers
  • Dependency policies
  • Release gates
  • Policy as Code
  • Risk acceptance
  • Ownership requirements

6. Monitor

Continuously monitor:

  • New dependencies
  • Vulnerabilities
  • Architecture drift
  • Ownership changes
  • Technical debt
  • Repository configuration
  • AI-generated changes
  • Build provenance

Framework Diagram

                     CODEBASE SAFETY
                           |
                     ┌─────┴─────┐
                     │ DISCOVER  │
                     └─────┬─────┘
                           ↓
                    ┌─────────────┐
                    │ UNDERSTAND  │
                    └──────┬──────┘
                           ↓
                    ┌─────────────┐
                    │   ASSESS    │
                    └──────┬──────┘
                           ↓
                    ┌─────────────┐
                    │  VALIDATE   │
                    └──────┬──────┘
                           ↓
                    ┌─────────────┐
                    │   GOVERN    │
                    └──────┬──────┘
                           ↓
                    ┌─────────────┐
                    │   MONITOR   │
                    └──────┬──────┘
                           │
                           └──────────────→ Continuous Risk Intelligence

The framework intentionally ends with monitoring.

A codebase is a moving target.

A dependency changes.

A developer leaves.

A repository becomes public.

An AI agent modifies a critical service.

A new vulnerability is disclosed.

A build pipeline changes.

Therefore, codebase safety must be continuously reassessed.

AI Code Audit vs. Traditional Code Review

Traditional code review and AI code auditing are related but different activities.

A pull request review asks:

“Is this change acceptable?”

A codebase assessment asks:

“What risks exist across this software asset?”

Both are necessary.

AI Code Audit vs. DevSecOps vs. Software Governance

These terms are sometimes used interchangeably, but they operate at different levels.

A mature organization connects all three.

What Are the Biggest Risks of an Unsafe Codebase?

The most obvious risk is a security vulnerability.

But the largest enterprise risks can be systemic.

1. Software Supply Chain Risk

Third-party packages, build systems, and deployment artifacts can introduce vulnerabilities or integrity concerns.

2. Architecture Drift

The implemented architecture can gradually diverge from the design.

3. Shadow AI

Developers may introduce AI tools or agents without organizational controls.

4. Undocumented Business Logic

Critical business rules can become embedded in code that few people understand.

5. Technical Debt

High debt can make security remediation and modernization increasingly expensive.

6. Weak Ownership

Nobody is accountable for remediation or long-term maintenance.

7. Insecure Defaults

Configuration and deployment assumptions can create vulnerabilities even when application logic is sound.

8. Compliance Gaps

An organization may be unable to demonstrate how software was built, who approved it, or what components it contains.

9. Operational Fragility

A system can be secure against attackers and still fail because of:

  • poor observability,
  • weak recovery,
  • single points of failure,
  • configuration dependencies,
  • unsupported infrastructure.

The Five Levels of Codebase Safety Maturity

Organizations generally move through five maturity stages.

Level 1: Initial

Security is primarily reactive.

Level 2: Assisted

Organizations introduce SAST, dependency scanning, secret detection, and automated testing.

Level 3: Standardized

Teams establish:

  • repository standards,
  • ownership,
  • branch protection,
  • security policies,
  • dependency policies.

Level 4: Automated

Controls become part of the engineering platform.

Examples:

  • Policy as Code
  • Automated release gates
  • Provenance
  • Continuous scanning
  • Automated dependency governance

Level 5: Intelligence-Driven

The organization can answer questions across the software estate:

  • Which applications contain a critical dependency?
  • Which business systems depend on it?
  • Who owns them?
  • Which ones are internet-facing?
  • Where is technical debt concentrated?
  • Which components have architecture risk?
  • Which changes were AI-generated?
  • Which risks are most material to the business?

That is the difference between security tooling and software intelligence.

What Should a Codebase Safety Assessment Produce?

A good assessment should not end with a 200-page vulnerability report.

It should produce a decision model.

At minimum:

Software Inventory

What software exists?

Security Risk Profile

What can be exploited?

Architecture Risk Profile

Where are structural weaknesses?

Dependency Risk Profile

What external components create risk?

Technical Debt Profile

Where is future change becoming expensive?

Ownership Map

Who controls each important component?

Provenance Assessment

Can we establish where software came from and how it was built?

AI Risk Profile

Where is AI-generated or AI-modified code entering the development lifecycle?

Remediation Roadmap

What should be fixed first?

The most important question is:

What should we fix first, why, and what happens if we do nothing?

Common Mistakes When Assessing Codebase Safety

Mistake 1: Assuming “No Critical CVEs” Means Safe

Vulnerability databases do not capture every form of software risk.

Mistake 2: Treating Test Coverage as Correctness

Coverage tells you what code was exercised.

It does not prove that the requirements were correctly implemented.

Mistake 3: Ignoring Architecture

A secure function inside an unsafe architecture remains part of an unsafe system.

Mistake 4: Ignoring Dependencies

Your organization may have written only 30% of the executable code.

Mistake 5: Ignoring Ownership

A vulnerability without an accountable owner can remain unresolved.

Mistake 6: Trusting AI Output

AI-generated code must be reviewed and tested.

Mistake 7: Measuring Developer Velocity Alone

More code does not automatically mean better software.

Mistake 8: Treating an SBOM as a Security Certificate

An SBOM is inventory.

It is not proof that every component is safe.

Mistake 9: Suppressing Findings Instead of Reducing Risk

A cleaner dashboard does not necessarily mean a safer application.

What Does the Future of Codebase Safety Look Like?

The traditional software lifecycle looked like:

Write Code
   ↓
Review
   ↓
Test
   ↓
Deploy
The emerging model is closer to:
Developer / AI Agent
        ↓
Continuous Analysis
        ↓
Security + Architecture + Dependencies
        ↓
Policy Evaluation
        ↓
Human Review
        ↓
Provenance
        ↓
Build
        ↓
Artifact Verification
        ↓
Deployment
        ↓
Continuous Monitoring

AI coding agents will make this shift more important.

As agents gain the ability to:

  • read repositories,
  • modify multiple files,
  • run commands,
  • create branches,
  • execute tests,
  • interact with tools,

the software-development control plane must evolve.

The important question becomes:

Can the organization verify what an agent changed and why?

Hashnode itself has recently added functionality oriented toward AI agents and machine-readable content, including support for retrieving article source Markdown and AI-agent access to its GraphQL API.

That broader trend illustrates where software ecosystems are heading: increasingly machine-readable systems interacting with increasingly autonomous software agents.

Software assurance will need to keep pace.

Key Takeaways

  1. A codebase is not safe simply because it has no critical vulnerabilities.
  2. Security is only one dimension of software risk.
  3. Architecture can create systemic risk even when individual functions are secure.
  4. Dependencies must be analyzed as part of the software supply chain.
  5. An SBOM provides inventory but does not prove software integrity.
  6. Software provenance is becoming increasingly important.
  7. Technical debt should be treated as a potential enterprise risk.
  8. Repository ownership is part of security governance.
  9. AI-generated code requires verification just like human-written code.
  10. Codebase safety should move from periodic assessment toward continuous software assurance.

The central idea is simple:

You do not know that your codebase is safe because a tool says “pass.” You know more about its safety when you can explain its material risks and demonstrate how those risks are controlled.

Conclusion

Modern software is too complex to evaluate through a single lens.

Security scanners are valuable.

Code reviews are valuable.

Unit tests are valuable.

Dependency scanners are valuable.

SBOMs are valuable.

AI coding assistants are valuable.

But none of them independently answers the larger question:

“Can we trust this software?”

Trust requires evidence.

You need to understand the code, its architecture, its dependencies, its provenance, its ownership, its technical debt, its security posture, and increasingly, how AI contributed to its creation.

That is where code intelligence becomes important.

The Code Registry approaches software analysis from this broader perspective: connecting source code, architecture, dependencies, technical debt, security, governance, and software risk rather than treating them as isolated technical metrics.

For teams responsible for business-critical software, the goal should not be to claim that a codebase is perfectly safe.

The goal should be to know:

· What is risky.

· Why it is risky.

· How much it matters.

· Who owns it.

· What controls exist.

· What needs to change.

That is a much more useful definition of software safety.

Frequently Asked Questions

Is my codebase safe if all tests pass?

No. Passing tests establish that tested scenarios behaved as expected; they do not prove security, architecture quality, dependency safety, provenance, or business correctness. A safer assessment combines testing with security analysis, architecture review, dependency intelligence, code-quality analysis, and governance evidence.

How do I perform a codebase security assessment?

Start by inventorying the repositories, applications, technologies, dependencies, and owners. Then analyze vulnerabilities, secrets, authentication, authorization, input validation, dependencies, configuration, and security-sensitive business logic. Validate important findings manually or dynamically and prioritize them according to exploitability and business impact.

Is SAST enough?

No. SAST is an important component of application security, but it cannot establish complete codebase safety. Static analysis should be complemented by dependency analysis, secrets detection, dynamic testing, architecture assessment, manual review, and runtime evidence.

Is an SBOM enough?

No. An SBOM answers the inventory question but not the complete trust question. You also need vulnerability intelligence, license information, dependency governance, provenance, and build-integrity evidence.

How should I review AI-generated code?

Review AI-generated code using the same engineering standards as human-written code, while paying additional attention to hallucinated APIs, dependencies, security patterns, incorrect assumptions, generated tests, and architecture consistency. The required review depth should increase with the impact of the change.

Can AI-generated code be trusted?

AI-generated code can be useful and production-ready, but it should not receive automatic trust. It must be validated through testing, code review, static analysis, dependency checks, and domain-specific verification.

What is software provenance?

Software provenance is verifiable information describing where, when, and how a software artifact was produced. It helps organizations establish traceability between source code, build processes, and delivered artifacts.

What is code intelligence?

Code intelligence connects source code with architecture, dependencies, ownership, security, quality, technical debt, and other software metadata. The objective is to understand software in context rather than analyzing isolated files or individual findings.

How does technical debt create security risk?

Technical debt can make software harder to understand, test, modify, and patch. Unsupported frameworks, excessive complexity, undocumented logic, and obsolete dependencies can increase the effort and risk associated with security remediation.

What is the difference between code review and codebase auditing?

Code review evaluates a specific change, while a codebase audit evaluates broader software risk. Code review asks whether a change should be accepted. A codebase audit asks what risks exist across the software asset and whether those risks are understood and controlled.

Sources and Further Reading

  • NIST Secure Software Development Framework (SSDF)
  • NIST SP 800–218
  • CNCF Software Supply Chain Security
  • SLSA Provenance
  • Google Open Source Security Team guidance
  • GitHub guidance on reviewing AI-generated code
  • Microsoft guidance on AI-assisted development and responsible code review
  • OWASP application-security guidance
  • CISA secure software and software supply-chain guidance

메타데이터
post_id
ed42e7c79cb0
slug
how-do-i-know-if-my-codebase-is-safe-ed42e7c79cb0
url
https://medium.com/@praveen_77839/how-do-i-know-if-my-codebase-is-safe-ed42e7c79cb0
canonical_url
https://medium.com/@praveen_77839/how-do-i-know-if-my-codebase-is-safe-ed42e7c79cb0
author_url
https://medium.com/@praveen_77839
status
ok
fetched_at
2026-08-22 22:30:06