Programming Fundamentals (Python/C++)

Chapter 15
Secure, Ethical, and Emerging Programming Practice

Bachelors Program in Full Stack Development
Programming Fundamentals (Python/C++)   •   Bachelor

Secure, Ethical, and Emerging Programming Practice

Introduction and Context

Programming is no longer concerned only with making a program produce the correct output. Software operates in environments containing personal information, financial records, intellectual property, public infrastructure, and services on which people depend. A program can therefore be technically functional while still being insecure, discriminatory, inaccessible, unlawful, or academically dishonest.

Professional programming practice combines correctness with security, ethics, maintainability, accountability, and social responsibility. These concerns apply equally to Python and C++, whether software is developed locally, in a cloud environment, with an artificial-intelligence coding assistant, or for a browser through WebAssembly.

This chapter presents practical principles for developing software responsibly. It also examines emerging tools and technologies whose benefits must be balanced against risks. The central idea is that a programmer is responsible not only for code that runs, but also for the consequences of how that code is designed, tested, deployed, reused, and governed.

Learning Objectives

By the end of this chapter, you should be able to:

1. Validate and safely handle untrusted input in Python and C++ programs.

2. Apply least privilege, secure defaults, dependency hygiene, and privacy-by-design.

3. Explain accessibility, software licensing, academic integrity, and responsible data practices.

4. Evaluate AI coding assistants, automated testing, and cloud development environments.

5. Describe the opportunities and constraints of WebAssembly, modern C++, and evolving Python.

6. Establish governance controls for code generated or substantially assisted by AI.

7. Analyze a software-development scenario using technical, ethical, and organizational criteria.

1. Security as a Programming Responsibility

1.1 Threats, vulnerabilities, and risk

A threat is a potential cause of harm, such as an attacker, accidental disclosure, or faulty automated process. A vulnerability is a weakness that can be exploited or can contribute to failure. Risk combines the likelihood of an adverse event with its potential impact. These terms should not be treated as interchangeable: a vulnerability may exist without having yet been exploited, and a threat may exist without a relevant vulnerability.

Security is best considered throughout the software development life cycle. Requirements should identify sensitive assets and trust boundaries; design should reduce attack surfaces; implementation should avoid unsafe operations; testing should seek misuse cases; deployment should restrict permissions; and maintenance should address newly discovered vulnerabilities.

A useful practical model is:

  • Assets: What must be protected? Examples include passwords, source code, payment data, and system availability.
  • Actors: Who may interact with the system, intentionally or accidentally?
  • Trust boundaries: Where does data or authority cross from one component to another?
  • Controls: Which technical and organizational measures reduce the risk?
  • Evidence: How will the team demonstrate that controls operate effectively?

1.2 Secure input handling

All input from users, files, networks, environment variables, APIs, and external libraries should be treated as untrusted until it has been checked for the operation being performed. Input validation should be based on an allowlist where feasible: specify the permitted type, length, range, structure, and character set rather than attempting to enumerate every malicious value.

Validation and output encoding solve different problems. Validation determines whether data is acceptable for a particular operation. Encoding transforms data safely for a particular context, such as HTML, a shell command, SQL, or a log file. A string that is valid as a person’s name is not automatically safe to insert into HTML or a command line.

A robust process is:

1. Parse input into an explicit type.

2. Reject malformed, excessive, or out-of-range values.

3. Normalize only when the intended meaning is clear.

4. Use parameterized interfaces rather than constructing commands or queries by concatenation.

5. Encode output for its destination context.

6. Handle errors without exposing secrets, stack traces, or internal paths.

For example, a Python database operation should use parameters:

```python

cursor.execute(

"SELECT id, email FROM users WHERE email = ?",

(email,)

)

```

The database driver treats `email` as data rather than as part of the SQL program. In C++, equivalent safety depends on the database library, but the same principle applies: use a prepared statement API.

Avoid shell interpolation when a library API is available. If a subprocess is necessary, pass an argument list rather than a single shell command string, restrict executable paths, and avoid accepting user input as an executable or option. In C++, unsafe memory operations also require attention. Prefer bounds-aware containers such as `std::vector` and `std::string`, use RAII for resource management, and avoid unchecked pointer arithmetic and lifetime errors.

1.3 Least privilege and secure defaults

Least privilege means that a user, process, service, or component receives only the authority necessary for its task and only for as long as necessary. A program that merely reads a configuration file should not have administrative privileges or write access to an entire filesystem.

Least privilege can be applied at several levels:

  • Operating-system accounts and filesystem permissions.
  • Database users restricted to required tables and operations.
  • Cloud identities with narrowly scoped roles.
  • Containers and processes with restricted capabilities.
  • Application roles that distinguish reading, editing, approving, and administering.

Secure defaults mean that the safest reasonable behavior occurs without requiring the user or administrator to discover hidden configuration. Examples include encrypted connections by default, disabled debug output in production, private rather than public cloud storage, and explicit opt-in for data collection.

Privilege reduction is not merely a security feature. It limits the effect of programming errors. If a vulnerable process cannot access unrelated records, the potential damage is reduced.

1.4 Secrets and cryptography

Passwords, API keys, signing keys, and database credentials should not be hard-coded in source code or committed to version control. Use a managed secret store or protected environment configuration, rotate credentials, and prevent secrets from appearing in logs and error reports.

Cryptographic algorithms should normally be provided by established libraries rather than implemented from scratch. Passwords should be stored using a password-hashing function designed for that purpose, with a unique salt for each password. Encryption provides confidentiality only when keys are properly generated, stored, rotated, and authorized. It does not by itself guarantee integrity, correct identity, or lawful processing.

2. Dependency Hygiene and Software Supply Chains

Modern programs depend on packages, compilers, operating-system components, container images, and build actions. Each dependency expands the software supply chain and may introduce vulnerabilities, malicious code, incompatible licensing, or maintenance risk.

Good dependency hygiene includes:

  • Select packages with credible maintenance, documentation, and security practices.
  • Pin or constrain versions reproducibly, while maintaining a planned update process.
  • Record direct and transitive dependencies.
  • Review security advisories and remove unused packages.
  • Verify package sources and protect build credentials.
  • Use lockfiles and reproducible builds where supported.
  • Scan dependencies, but treat scanners as aids rather than proof of safety.
  • Test updates before production deployment.

Pinning every dependency forever is not a complete strategy: it improves reproducibility but can preserve known vulnerabilities. Conversely, automatically accepting every update may introduce breaking changes or malicious releases. A mature process combines controlled versioning, monitoring, testing, and timely remediation.

A software bill of materials (SBOM) records the components in a product. It assists incident response by helping an organization identify whether a vulnerable library is present. An SBOM does not make components secure; it improves visibility and response capability.

3. Privacy and Responsible Data Practices

Privacy concerns how personal data is collected, used, shared, retained, and deleted. Responsible programming begins by asking whether data is needed at all. Data minimization reduces both ethical exposure and security impact.

A privacy-conscious design should define:

  • The purpose for collecting each data item.
  • The lawful or organizational basis for processing, where applicable.
  • Data quality and correction procedures.
  • Retention and deletion periods.
  • Access controls and audit records.
  • Whether data is transferred to vendors or across jurisdictions.
  • How individuals can understand and exercise relevant rights.

Collecting an email address for account recovery does not automatically justify using it for unrelated marketing. Consent, where relied upon, should be informed, specific, and revocable rather than hidden in a confusing interface.

Sensitive data should be encrypted in transit and at rest when appropriate, access should be logged, and test environments should use synthetic or properly de-identified data. De-identification is not always irreversible: combining supposedly anonymous records with external datasets may re-identify people. Consequently, teams should assess the residual risk rather than assuming that removing names is sufficient.

Algorithmic systems also raise fairness concerns. A model or rule may produce unequal outcomes because of biased training data, proxy variables, measurement errors, or unequal access to the system. Developers should document intended use, limitations, evaluation populations, and appeal or human-review mechanisms. Fairness cannot be established by a single numerical test in every context; the relevant harms and affected groups must be considered.

4. Accessibility and Inclusive Software

Accessibility means that people with different sensory, motor, cognitive, and communication abilities can use a system. It is a quality attribute and, in many contexts, a legal and contractual obligation.

Programming practices that improve accessibility include semantic HTML, keyboard operability, visible focus indicators, sufficient text contrast, meaningful labels, captions and transcripts, descriptive alternative text, scalable text, and clear error messages. In desktop or mobile applications, controls should expose appropriate names and states to assistive technologies.

Accessibility should be tested early. Automated tools can detect some missing labels or contrast problems, but they cannot determine whether a workflow is understandable with a keyboard or screen reader. Testing with users with disabilities is therefore valuable. Accessibility is not an optional final polish: retrofitting it after architecture and interface decisions are fixed is more expensive and less effective.

5. Licensing, Attribution, and Academic Integrity

A license grants permissions and imposes conditions concerning software use, modification, distribution, and sometimes patent rights or disclosure of source code. Copyright generally protects the expression of software, while a license determines how others may use that expression.

Common open-source license families differ. Permissive licenses generally allow broad reuse subject to conditions such as attribution and preservation of notices. Copyleft licenses may require derivative distributions to provide corresponding source under specified terms. The exact obligations depend on the license text and the manner of combination and distribution; labels such as “open source” do not mean “without conditions.”

Professional practice requires an inventory of third-party code and data, preservation of notices, compliance with attribution and source-disclosure requirements, and review of incompatible licenses. Never copy code merely because it is visible online. License compliance and plagiarism are separate issues: code can be permissively licensed yet still require attribution in an academic assignment.

Academic integrity requires that submitted work represent the student’s permitted contribution. Unauthorized copying, fabrication of results, contract cheating, and undisclosed assistance violate academic standards. AI assistance must be used according to course policy. A student who uses a tool to generate a solution remains responsible for understanding, testing, citing, and defending that solution.

6. Testing, Assurance, and Responsible Automation

Automated testing provides repeatable evidence that specified behaviors continue to work. Unit tests examine small components; integration tests examine interactions; system or end-to-end tests examine complete workflows. Property-based testing generates many inputs to test general properties, while static analysis examines code without executing it.

Testing is not equivalent to proving the absence of defects. A test can demonstrate that a particular behavior occurred under particular conditions; it cannot establish that no untested condition will fail. Test suites should include normal cases, boundary values, malformed input, authorization failures, timeouts, resource exhaustion, and privacy-sensitive behavior.

For example, a function accepting a positive integer should be tested with a typical valid value, the smallest valid value, zero, negative values, very large values, non-integer input, and values that could cause excessive resource use. Tests should assert security properties as well as output values: an unauthorized user must be denied, and a failed operation must not leave a partial update.

Continuous integration can run formatting checks, linters, static analysis, dependency scans, unit tests, and build verification on each change. However, automated gates should be interpreted by qualified people. A tool may report false positives, miss business-logic flaws, or encourage teams to optimize for a metric rather than actual quality.

7. Evaluating AI Coding Assistants

AI coding assistants can generate code, tests, explanations, documentation, and refactoring suggestions. They may improve productivity, support learning, and help developers explore unfamiliar APIs. They can also produce insecure, incorrect, obsolete, biased, or license-incompatible material with convincing confidence.

A responsible evaluation framework asks:

1. Purpose: Is the tool being used for learning, drafting, translation, testing, or production code?

2. Data exposure: Will prompts contain personal data, confidential code, credentials, or proprietary requirements?

3. Reliability: Has the output been reviewed, executed, tested, and compared with authoritative documentation?

4. Security: Does the code validate input, handle errors, protect secrets, and enforce authorization?

5. Provenance: Can the organization identify generated sections, model versions, prompts, and human reviewers where necessary?

6. Licensing and policy: Are tool terms, organizational rules, and third-party rights satisfied?

7. Accountability: Who approves the result and responds if it causes harm?

Generated code should be treated as an untrusted draft, not as an authority. A reviewer should understand every important line, run tests including adversarial cases, use static and dependency analysis, and inspect for accidental data disclosure. Prompts should be minimized and sanitized. Organizations should define approved tools, prohibited data, retention expectations, review thresholds, and incident procedures.

Governance does not require recording every trivial autocomplete in the same way as a generated security module. Proportional controls are appropriate: higher-risk systems require stronger review, traceability, testing, and approval.

8. Cloud Development Environments

Cloud development environments provide remote workspaces, hosted repositories, collaborative tools, and scalable build resources. They support consistent configuration and access from multiple devices, but they also create risks involving identity, secrets, data location, vendor dependency, and accidental public exposure.

Best practices include multifactor authentication, short-lived credentials, role-based access, private repositories by default, encrypted connections, protected branches, isolated build environments, resource quotas, audit logs, and explicit policies for copying production data into development. Developers should verify that terminal histories, logs, notebooks, and temporary files do not contain secrets.

A cloud workspace is not automatically secure because a reputable provider operates it. Responsibility is shared: the provider secures certain infrastructure, while the customer configures identities, applications, data, and access policies. Teams should understand the division of responsibility and maintain a recovery plan independent of a single vendor.

9. WebAssembly and Contemporary Language Practice

WebAssembly (Wasm) is a portable, low-level compilation target designed for efficient execution in environments such as web browsers and server runtimes. Languages including C++ and Rust can compile to Wasm, while JavaScript commonly coordinates interaction with browser APIs. Wasm modules operate within a sandboxed execution model, but sandboxing is not a substitute for authorization, input validation, or careful resource management.

Wasm can enable near-native computational performance, code reuse across platforms, and client-side execution. Limitations include binary size, startup cost, restricted direct access to host resources, interoperability complexity, and the need to manage memory and security boundaries between the module and its host. A module should receive only the imports and capabilities it needs.

Modern C++ emphasizes resource safety and expressive abstractions while retaining systems-level control. Important practices include RAII, smart pointers for ownership, move semantics, `std::span` for non-owning views with explicit bounds, standard containers, const-correctness, and compiler warnings. Modern features do not eliminate undefined behavior; lifetime, concurrency, integer, and bounds errors remain possible. Code should be compiled with appropriate warnings and sanitizers during development.

Python continues to evolve with features such as improved type annotations, structural pattern matching, asynchronous programming support, dataclasses, and performance-oriented interpreter developments. Type hints assist tools and communication but do not automatically validate runtime input. Python’s dynamic nature makes explicit validation, tests, dependency management, and clear interfaces especially important. Language version changes should be tracked because syntax, standard-library behavior, and package compatibility evolve.

10. Governance of Generated and High-Impact Code

Governance translates principles into repeatable decisions. A lightweight governance process for generated or high-impact code can include:

  • Classifying the system according to sensitivity and potential harm.
  • Recording requirements, data sources, dependencies, and significant design decisions.
  • Identifying human owners and approval authority.
  • Requiring code review and security testing proportional to risk.
  • Maintaining provenance for generated artifacts and external components.
  • Monitoring production behavior and reporting incidents.
  • Providing rollback, correction, and decommissioning procedures.

Regulatory obligations vary by jurisdiction and sector. Privacy, accessibility, consumer protection, cybersecurity, records management, and software licensing may all apply. Developers should not assume that technical feasibility establishes legal permission. When requirements are uncertain, consult institutional policy, legal specialists, security professionals, and affected stakeholders.

Applied Case: Illustrative University Health-Appointment Platform

Background

A university team builds a Python web service that allows students to request health appointments. The service uses a cloud database and an AI coding assistant. A C++ module calculates appointment availability for a separate campus kiosk.

Problem

During review, the team discovers that the prototype stores unencrypted medical notes in a development database, uses an administrator database account, constructs a query with string concatenation, and sends complete error traces to browsers. The AI assistant generated much of the authentication code, but the team has no record of prompts or review decisions. The kiosk also assumes that all input is numeric and crashes on malformed data.

Analysis

The system handles sensitive personal information and therefore has high consequences for confidentiality and trust. The administrator account violates least privilege. Query concatenation creates injection risk. Detailed traces disclose internal information. Using real health notes in development violates data minimization and increases exposure. The absence of provenance does not itself prove that generated code is defective, but it weakens accountability and makes review difficult. The kiosk’s assumption about numeric input is unsafe because external input can be malformed or deliberately hostile.

Approach and Solution

The team first classifies the data and defines a minimum necessary data model. Synthetic records replace real notes in development. A dedicated database identity receives only the required operations, and sensitive fields are encrypted using an approved key-management service. Parameterized queries replace concatenation, while generic user-facing errors are separated from detailed, access-controlled logs.

The C++ module parses input using a checked conversion, rejects values outside the permitted range, and tests malformed, boundary, and oversized values. Ownership and buffers use standard library abstractions, and sanitizers are enabled in development. Authentication and authorization are reviewed against authoritative framework documentation rather than accepted solely because an AI assistant produced the code.

The team records the approved AI tool, categories of use, human reviewers, dependency versions, and test evidence. Automated tests cover authorization, injection attempts, logging behavior, encryption configuration, and kiosk failure cases. A privacy review establishes retention and deletion rules, while an accessibility review tests keyboard navigation, labels, contrast, and screen-reader output.

Outcome

The revised system has a smaller attack surface, reduced development-data exposure, clearer accountability, and more predictable failure behavior. The team also discovers that a planned analytics feature is unnecessary for the service’s purpose and removes it, reducing collection and retention.

Learning Points

Security controls are most effective when introduced before deployment. AI assistance does not transfer responsibility away from developers. Privacy, accessibility, licensing, testing, and governance are interconnected: a technically secure system can still be unacceptable if it excludes users, misuses data, or violates obligations.

Challenges and Limitations

No checklist guarantees secure or ethical software. New vulnerabilities appear after release; dependency scanners have incomplete knowledge; tests may miss unusual interactions; and accessibility or fairness depends partly on context and lived experience. Encryption can complicate recovery, least privilege can create operational friction, and detailed audit logs may themselves contain sensitive information. Excessive governance can slow experimentation, while insufficient governance can create untraceable and harmful systems.

The appropriate response is risk-based, iterative practice. Teams should make assumptions explicit, seek review from people with relevant expertise, involve affected users, monitor real-world behavior, and revise systems when evidence changes. Professional judgment remains necessary even when standards, tools, and automated assistants are available.

Best-Practice Checklist

Before releasing a program, ask:

  • Are all external inputs parsed, bounded, validated, and safely encoded?
  • Are privileges, secrets, logs, and error messages appropriately restricted?
  • Are dependencies known, maintained, scanned, and licensed correctly?
  • Is personal data necessary, protected, accurate, retained only as needed, and accessible for legitimate rights?
  • Can people with disabilities use the system?
  • Are code origin, AI assistance, and human approvals documented where required?
  • Do tests include misuse, boundary, authorization, failure, and recovery cases?
  • Are cloud identities, repositories, workspaces, and build artifacts protected?
  • Have emerging-platform limitations and language-version changes been assessed?
  • Is there a plan for monitoring, incident response, correction, rollback, and decommissioning?

Chapter Summary

Secure programming treats every external input as untrusted, applies validation and context-specific encoding, uses parameterized interfaces, protects secrets, and limits authority through least privilege and secure defaults. Dependency hygiene reduces supply-chain risk through informed selection, controlled updates, inventories, and vulnerability response.

Responsible programming also protects privacy through minimization, purpose limitation, retention control, access management, and careful treatment of sensitive or inferred data. Accessibility and inclusive design make software usable by people with varied abilities. Licensing and academic integrity require attribution, compliance with reuse conditions, and honest disclosure of assistance.

Automated testing, static analysis, and continuous integration provide valuable evidence but cannot replace human judgment. AI coding assistants, cloud environments, WebAssembly, modern C++, and evolving Python create important opportunities alongside risks involving security, provenance, privacy, interoperability, and accountability. Governance should therefore classify risk, document decisions, require proportionate review, and maintain monitoring and recovery processes. The professional programmer is accountable for the behavior and consequences of the complete software system.

Key Terms

Threat: A potential cause of harm to a system or stakeholder.

Vulnerability: A weakness that may be exploited or contribute to failure.

Attack surface: The set of interfaces and components through which a system can be affected.

Input validation: Checking data against required type, structure, range, and business rules.

Output encoding: Transforming data safely for a specific destination context.

Least privilege: Granting only the authority necessary for a task and duration.

Secure default: A configuration that selects the safer behavior without extra user action.

Secret: Confidential authentication or cryptographic material such as a key or token.

Dependency hygiene: Practices for selecting, tracking, updating, and securing software components.

SBOM: A software bill of materials listing components in a product.

Privacy by design: Integrating privacy protections into architecture and development.

Data minimization: Collecting and retaining only data necessary for a defined purpose.

Accessibility: The ability of people with varied abilities to use a system.

Software license: Legal terms governing use, modification, and distribution of software.

Academic integrity: Honest representation of a learner’s permitted work and sources.

Static analysis: Examination of code without executing it.

WebAssembly: A portable low-level code format for sandboxed execution environments.

Provenance: Records showing the origin, transformation, and review of an artifact.

Governance: Policies, roles, controls, and evidence used to direct and oversee software practice.

Review Questions

Short Answer Questions

1. Distinguish a threat from a vulnerability and give one example of each.

2. Why are validation and output encoding different security activities?

3. Explain the principle of least privilege in relation to a database account.

4. Why does pinning dependency versions not eliminate supply-chain risk?

5. State two responsibilities that remain with a developer who uses an AI coding assistant.

Long Answer Questions

1. Explain how security, privacy, accessibility, licensing, and academic integrity should be incorporated across the software development life cycle.

2. Compare the benefits and limitations of automated testing, static analysis, and human code review.

3. Discuss a responsible organizational policy for using AI-generated code in production systems.

4. Explain the main opportunities and constraints associated with cloud development environments and WebAssembly.

5. Describe how modern C++ and Python practices can reduce programming risk while acknowledging their limitations.

Analytical / Application Questions

1. A Python application accepts a filename from a web form and passes it to a shell command. Analyze the risks and propose a safer design.

2. A university wants to use real student records to test an AI-supported analytics feature. Evaluate the proposal using privacy, security, governance, and academic-integrity principles.

3. A C++ kiosk crashes when users enter unexpected text and runs under an administrator account. Develop a prioritized remediation plan and explain how you would verify it.

Multiple Choice Questions with Answers

Question 1

Which practice most directly prevents SQL injection when user input is used in a query?

A. Increasing the database server memory

B. Using parameterized queries

C. Printing the query in an error message

D. Storing the query in a longer string

Correct Answer: B. Using parameterized queries

Question 2

What does least privilege require?

A. Every process should run as an administrator

B. Users should share one powerful account

C. Each component should receive only necessary authority

D. Permissions should never be changed

Correct Answer: C. Each component should receive only necessary authority

Question 3

Which statement about dependency pinning is correct?

A. It guarantees that dependencies contain no vulnerabilities

B. It improves reproducibility but may preserve known vulnerabilities

C. It removes the need for dependency inventories

D. It makes license review unnecessary

Correct Answer: B. It improves reproducibility but may preserve known vulnerabilities

Question 4

Which example best demonstrates data minimization?

A. Collecting every available field for possible future use

B. Retaining all records indefinitely

C. Collecting only information necessary for a defined purpose

D. Publishing raw data after removing passwords

Correct Answer: C. Collecting only information necessary for a defined purpose

Question 5

Why should AI-generated code be treated as a draft?

A. It cannot be compiled under any circumstances

B. It may contain incorrect, insecure, or unsuitable recommendations

C. It is always illegally copied

D. It never produces documentation

Correct Answer: B. It may contain incorrect, insecure, or unsuitable recommendations

Question 6

Which control is most appropriate for protecting a production API key?

A. Embedding it in a public source file

B. Printing it in application logs

C. Committing it to a shared repository

D. Storing it in a protected secret-management system

Correct Answer: D. Storing it in a protected secret-management system

Question 7

What is a limitation of automated accessibility testing?

A. It can detect every usability barrier

B. It eliminates the need for user testing

C. It detects some issues but cannot assess every real interaction

D. It only works for C++ programs

Correct Answer: C. It detects some issues but cannot assess every real interaction

Question 8

What is an SBOM primarily used for?

A. Listing the software components in a product

B. Encrypting user passwords

C. Replacing all security testing

D. Generating user-interface colors

Correct Answer: A. Listing the software components in a product

Question 9

Which statement about type hints in Python is most accurate?

A. They automatically validate all runtime input

B. They assist communication and tooling but do not alone enforce runtime validation

C. They prevent every dependency vulnerability

D. They make testing unnecessary

Correct Answer: B. They assist communication and tooling but do not alone enforce runtime validation

Question 10

Which is a major responsibility when deploying WebAssembly modules?

A. Granting every module unrestricted host access

B. Ignoring resource limits because sandboxing solves all risks

C. Restricting imports and capabilities to those actually required

D. Disabling all input validation

Correct Answer: C. Restricting imports and capabilities to those actually required

Programming Fundamentals (Python/C++)
Chapter 15 of 15