update
Some checks failed
Build Quartz Notes / build (push) Failing after 21s

This commit is contained in:
2026-06-10 20:00:45 +01:00
parent 5d3ed14275
commit 9645ee23b0
295 changed files with 2044 additions and 33 deletions

0
Career/AI/AI - Codex.md Executable file → Normal file
View File

0
Career/AI/AI Moc.md Executable file → Normal file
View File

0
Career/AI/Data camp AI training.md Executable file → Normal file
View File

0
Career/API/API Architecture.md Executable file → Normal file
View File

0
Career/API/ASP.NET Core Web API Fundamental Notes.md Executable file → Normal file
View File

0
Career/API/Restful API.md Executable file → Normal file
View File

0
Career/Attachments/APIOps.png Executable file → Normal file
View File

Before

Width:  |  Height:  |  Size: 154 KiB

After

Width:  |  Height:  |  Size: 154 KiB

0
Career/Attachments/Big-O-Notation-3130482830.png Executable file → Normal file
View File

Before

Width:  |  Height:  |  Size: 232 KiB

After

Width:  |  Height:  |  Size: 232 KiB

0
Career/Attachments/Screenshot 2026-01-14 154800.png Executable file → Normal file
View File

Before

Width:  |  Height:  |  Size: 171 KiB

After

Width:  |  Height:  |  Size: 171 KiB

0
Career/Attachments/adapter-pattern-2.png Executable file → Normal file
View File

Before

Width:  |  Height:  |  Size: 56 KiB

After

Width:  |  Height:  |  Size: 56 KiB

0
Career/Attachments/adapter-pattern.png Executable file → Normal file
View File

Before

Width:  |  Height:  |  Size: 113 KiB

After

Width:  |  Height:  |  Size: 113 KiB

0
Career/Attachments/command-pattern.png Executable file → Normal file
View File

Before

Width:  |  Height:  |  Size: 134 KiB

After

Width:  |  Height:  |  Size: 134 KiB

0
Career/Attachments/composite-pattern.png Executable file → Normal file
View File

Before

Width:  |  Height:  |  Size: 90 KiB

After

Width:  |  Height:  |  Size: 90 KiB

0
Career/Attachments/decorator-pattern.png Executable file → Normal file
View File

Before

Width:  |  Height:  |  Size: 43 KiB

After

Width:  |  Height:  |  Size: 43 KiB

0
Career/Attachments/decorator-problem.png Executable file → Normal file
View File

Before

Width:  |  Height:  |  Size: 41 KiB

After

Width:  |  Height:  |  Size: 41 KiB

0
Career/Attachments/facade-pattern.png Executable file → Normal file
View File

Before

Width:  |  Height:  |  Size: 110 KiB

After

Width:  |  Height:  |  Size: 110 KiB

0
Career/Attachments/factory-pattern.png Executable file → Normal file
View File

Before

Width:  |  Height:  |  Size: 108 KiB

After

Width:  |  Height:  |  Size: 108 KiB

0
Career/Attachments/iterator-pattern.png Executable file → Normal file
View File

Before

Width:  |  Height:  |  Size: 126 KiB

After

Width:  |  Height:  |  Size: 126 KiB

0
Career/Attachments/observer-pattern.png Executable file → Normal file
View File

Before

Width:  |  Height:  |  Size: 118 KiB

After

Width:  |  Height:  |  Size: 118 KiB

0
Career/Attachments/proxy-pattern.png Executable file → Normal file
View File

Before

Width:  |  Height:  |  Size: 66 KiB

After

Width:  |  Height:  |  Size: 66 KiB

0
Career/Attachments/singleton-pattern.png Executable file → Normal file
View File

Before

Width:  |  Height:  |  Size: 49 KiB

After

Width:  |  Height:  |  Size: 49 KiB

0
Career/Attachments/state-pattern.png Executable file → Normal file
View File

Before

Width:  |  Height:  |  Size: 143 KiB

After

Width:  |  Height:  |  Size: 143 KiB

0
Career/Attachments/structure-pattern.png Executable file → Normal file
View File

Before

Width:  |  Height:  |  Size: 9.8 KiB

After

Width:  |  Height:  |  Size: 9.8 KiB

0
Career/Attachments/template-method-pattern.png Executable file → Normal file
View File

Before

Width:  |  Height:  |  Size: 50 KiB

After

Width:  |  Height:  |  Size: 50 KiB

0
Career/Big (O) - Time and Space Complexity.md Executable file → Normal file
View File

0
Career/Bowling Kata.md Executable file → Normal file
View File

0
Career/Career MOC.md Executable file → Normal file
View File

5
Career/Concepts.md Executable file → Normal file
View File

@@ -57,10 +57,8 @@ Some core programming concepts that are essential for software development. The
# Misc
- [[Windows Services]]
- [[DLL's]]
-
- [[Regex]]
# Security:
- [[OWASP Top 10]]
@@ -132,6 +130,7 @@ Some core programming concepts that are essential for software development. The
- [ ] Turing machines
- [ ] computability theory
- [x] MVPs and MVTs
- [x] Regex
# Data view query

0
Career/DLL's.md Executable file → Normal file
View File

0
Career/Database - SQL/Airflow Dags.md Executable file → Normal file
View File

0
Career/Database - SQL/Airflow Tasks.md Executable file → Normal file
View File

0
Career/Database - SQL/Airflow.md Executable file → Normal file
View File

View File

Before

Width:  |  Height:  |  Size: 447 KiB

After

Width:  |  Height:  |  Size: 447 KiB

0
Career/Database - SQL/Database MOC.md Executable file → Normal file
View File

View File

0
Career/Database - SQL/Postgres.md Executable file → Normal file
View File

0
Career/Database - SQL/SQL Joins.md Executable file → Normal file
View File

View File

@@ -265,5 +265,840 @@ genre | avg_cost
Family | 2000000
```
# Constraints
## Example Table (Promotions)
```
CREATE TABLE Promotions (
    id INT PRIMARY KEY,
    name VARCHAR(100) NOT NULL,
    category VARCHAR(50) NOT NULL,
    CONSTRAINT unique_name_category
        UNIQUE (name, category)
);
```
## Purpose of Constraints
- Prevent **invalid or unwanted data**
- Enforce **rules on table columns**
- Improve **data integrity**
## NOT NULL
- Prevents a column from storing `NULL` values
- Use when a value is required
`name VARCHAR(100) NOT NULL`
## UNIQUE
- Ensures all values in a column are **distinct**
- Prevents duplicate entries
`name VARCHAR(100) UNIQUE`
### Composite UNIQUE
- Enforces uniqueness across multiple columns
`UNIQUE (name, category)`
- Same name allowed if category differs
- Same category allowed if name differs
- Duplicate combinations are not allowed
## Multiple Constraints on a Column
- You can combine constraints:
`name VARCHAR(100) NOT NULL UNIQUE`
## Named Constraints
- Assign custom names for easier maintenance
`CONSTRAINT unique_name UNIQUE (name)`
## Column vs Table Constraints
- Column constraint: defined inline
- Table constraint: defined separately
Both work the same, except:
- `NOT NULL` must be defined at the column level
## PRIMARY KEY
- Uniquely identifies each row
- Automatically enforces:
- NOT NULL
- UNIQUE
`id INT PRIMARY KEY`
### Key Rules
- Only one primary key per table
- Can consist of one or multiple columns
## PRIMARY KEY vs UNIQUE + NOT NULL
- Both enforce uniqueness and no nulls
- Difference:
- PRIMARY KEY: only one per table
- UNIQUE + NOT NULL: can use multiple columns
# Value Constraints (Foreign Key & CHECK)
## Example Tables (Movies + Promotions)
```
CREATE TABLE Movies (
    id INT PRIMARY KEY,
    title VARCHAR(100) NOT NULL,
    duration INT CHECK (duration > 0)
);
CREATE TABLE Promotions (
    id INT PRIMARY KEY,
    name VARCHAR(100) NOT NULL,
    category VARCHAR(50) NOT NULL,
    movie_id INT,
    CONSTRAINT fk_movie
        FOREIGN KEY (movie_id)
        REFERENCES Movies(id),
    CONSTRAINT unique_name_category
        UNIQUE (name, category)
);
```
## Foreign Key (FK)
### Definition
- A **foreign key** is a column in one table that references a **primary key in another table**
- Used to **link tables** and avoid duplicating data
`movie_id INT REFERENCES movies(id)`
This is the same as:
`movie_id INT REFERENCES movies`
## Naming Convention
- Format: `referencedTable_singular + _id`
Examples:
- `movie_id` → references Movies(id)
- `user_id` → references Users(id)
## Why Use Foreign Keys
- Prevents **invalid references**
- Ensures **data integrity**
- Avoids **duplicating data across tables**
## Behaviour Without FK
- You can insert invalid data:
`movie_id = 999  -- even if it doesn't exist`
- Creates **bad data**
## Behaviour With FK
- Database **blocks invalid inserts**
`INSERT INTO Promotions (id, name, category, movie_id)`
`VALUES (1, 'Half Off', 'Discount', 999);  -- fails`
- Error: violates foreign key constraint
## Table Creation Order Rule
- The referenced table **must be created first**
`CREATE TABLE Movies (...)`
`CREATE TABLE Promotions (... REFERENCES Movies)`
## Table Constraint Version
```
FOREIGN KEY (movie_id) REFERENCES movies
```
## Orphan Records
### Definition
- A row that references data that **no longer exists**
Example:
- Movie deleted
- Promotion still points to that movie_id
## How FK Prevents Orphans
- Prevents deleting parent rows if children exist
`DELETE FROM Movies WHERE id = 6;  -- fails if Promotions reference it`
- You must:
1. Delete child rows first
2. Then delete parent
## Dropping Tables
- Cannot drop a table if another table depends on it
`DROP TABLE Movies;  -- fails if Promotions references it`
- Must drop dependent tables first
## CHECK Constraint
### Definition
- Validates column values using a condition
`salary int CHECK (salary > 500)`
## Purpose of CHECK
- Prevent logically invalid data
Example:
- Duration cannot be negative
## Behaviour
```
INSERT INTO Movies (id, title, duration)
VALUES (1, 'Test Movie', -10);  -- fails
```
## Example Inserts
### Valid Movie
```
INSERT INTO Movies (id, title, duration)
VALUES (1, 'Gone With the Wind', 240);
```
### Valid Promotion
```
INSERT INTO Promotions (id, name, category, movie_id)
VALUES (1, 'Matinee', 'Discount', 1);
```
### Fails (invalid foreign key)
```
INSERT INTO Promotions (id, name, category, movie_id)
VALUES (2, 'Half Off', 'Discount', 999);
```
### Fails (negative duration)
```
INSERT INTO Movies (id, title, duration)
VALUES (2, 'Bad Movie', -10);
```
# SQL Relationships & Normalization (Level 3 Notes)
## Overview
- Focus: **Database relationships** and **normalization** to improve data integrity and flexibility.
- Example context: A **Movies application** where each movie can have **multiple genres**.
## Problem with Current Design
- Storing multiple genres in one column (e.g., `"Adventure, Fantasy"`) causes issues:
- Hard to query (e.g., finding all _Adventure_ movies).
- Difficult to update individual values.
- Violates normalization rules.
### Example Issue
`SELECT * FROM Movies WHERE genre = 'Adventure';`
- Returns movies with only `"Adventure"`, but **misses movies** like `"Adventure, Fantasy"`.
## Normalization Basics
### First Normal Form (1NF)
- Rule: **No repeating groups in a column**.
- Each field should contain a **single value (atomic)**.
#### Fix
Split rows so each genre is separate:
|title|genre|duration|
|---|---|---|
|Peter Pan|Adventure|120|
|Peter Pan|Fantasy|120|
- Eliminates multi-value columns.
- **Still problematic**: duplicate movie data.
### Second Normal Form (2NF)
- Rule: **No redundancy (no repeated unnecessary data)**.
- Each piece of information should be stored **once**.
#### Problem in 1NF Table
- Movie details (e.g., duration) are duplicated across rows.
## Solution: Table Decomposition
### Step 1: Create a Movies Table
- Store unique movies only.
|id|title|duration|
|---|---|---|
|1|Don Juan|110|
|2|Peter Pan|120|
### Step 2: Create a Genres Table
- Store each genre once.
|id|name|
|---|---|
|1|Romance|
|2|Adventure|
|3|Fantasy|
### Step 3: Create a Join Table (Many-to-Many)
- Name convention: `movies_genres`
- Purpose: Link movies to genres.
|movie_id|genre_id|
|---|---|
|1|1|
|2|2|
|2|3|
- `movie_id` → references `Movies.id`
- `genre_id` → references `Genres.id`
- Both are **foreign keys**
## Benefits of This Design
- No duplication (meets 2NF).
- Easy updates:
- Change movie duration in one place.
- Add/remove genres without affecting other data.
- Scalable for complex relationships.
## Querying the Data
### Step-by-step (manual approach)
1. Get movie ID:
`SELECT id FROM Movies WHERE title = 'Peter Pan';`
2. Get associated genre IDs:
`SELECT genre_id FROM movies_genres WHERE movie_id = 2;`
3. Get genre names:
`SELECT name FROM Genres WHERE id IN (2, 3);`
### Simplified Query Using `IN`
`SELECT name FROM Genres WHERE id IN (2, 3);`
## Example Operation
### Add a new genre to a movie
```
Add "Fantasy" to "Robin Hood":
INSERT INTO movies_genres (movie_id, genre_id)
VALUES (4, 3);
```
## Key Takeaways
- Avoid storing multiple values in a single column.
- Use **normalization** to:
- Eliminate redundancy
- Improve data consistency
- Use **join tables** for many-to-many relationships.
- Trade-off: Queries become slightly more complex, but data becomes more robust and flexible.
# Database Relationships
## Overview
There are three fundamental relationship types between tables:
1. **One-to-One (1:1)**
2. **One-to-Many (1:N)**
3. **Many-to-Many (N:N)**
## 1. One-to-Many (1:N)
### Definition
- A single row in Table A can relate to **multiple rows** in Table B.
- A row in Table B relates to **only one row** in Table A.
### Key Implementation
- Add a **foreign key** in the "many" table.
### Example
- **Movies → Promotions**
- One movie can have many promotions.
- Each promotion belongs to one movie.
`Movies (id) ← Promotions (movie_id)`
### Diagram Representation
- `1` on the "one" side
- `*` on the "many" side
## 2. Many-to-Many (N:N)
### Definition
- Multiple rows in Table A can relate to multiple rows in Table B.
### Key Implementation
- Requires a **join table (junction table)** that holds foreign keys from both tables.
### Example
- **Movies ↔ Genres**
- A movie can have many genres.
- A genre can belong to many movies.
```
Movies_Genres
- movie_id
- genre_id
```
### Diagram Representation
- `*` on both sides
- Join table is typically implied (not always shown explicitly)
## 3. One-to-One (1:1)
### Definition
- A row in Table A relates to exactly **one row** in Table B.
### Use Case
- Used to split large or complex tables into smaller ones.
### Example
- **Customers ↔ Addresses**
- Each customer has one address.
- Each address belongs to one customer.
`Customers (address_id) → Addresses (id)`
### Diagram Representation
- `1` on both sides
## Relationship Identification Examples
### Example 1: Movies & Reviews
- One movie can have many reviews.
- Each review belongs to one movie.
**Relationship:** One-to-Many
`Movies (id) ← Reviews (movie_id)`
### Example 2: Movies & Promotions
- A promotion can apply to many movies.
- A movie can have many promotions.
**Relationship:** Many-to-Many
```
Movies_Promotions
- movie_id
- promotion_id
```
## Summary
|Relationship Type|Key Idea|Implementation|
|---|---|---|
|One-to-One|1 row ↔ 1 row|Foreign key on one side|
|One-to-Many|1 row → many rows|Foreign key in "many" table|
|Many-to-Many|Many ↔ many|Join table with two FKs|
- Always identify how entities relate **from a business perspective**, not just technically.
- Use:
- **Foreign keys** for 1:1 and 1:N
- **Join tables** for N:N
- Diagrams use:
- `1` = single
- `*` = many
# SQL INNER JOINs (Level 4 Notes)
## Overview
- **INNER JOIN** is used to combine rows from two (or more) tables based on a related column.
- It returns **only the matching records** between the tables (the overlapping part).
- Common use case: retrieving related data in a **single query instead of multiple queries**.
## Key Concepts
### 1. Problem Without JOIN
- To get reviews and corresponding movie titles:
1. Query reviews: SELECT review, movie_id FROM Reviews;
2. Use returned `movie_id`s to query movies: SELECT title FROM Movies WHERE id IN (1, 3, 4);
- This requires **multiple queries**, which is inefficient.
### 2. INNER JOIN Syntax
```
SELECT *
FROM Movies
INNER JOIN Reviews
ON Movies.id = Reviews.movie_id;
```
#### Explanation:
- `INNER JOIN Reviews`: specifies the table to join.
- `ON Movies.id = Reviews.movie_id`: defines how rows relate:
- `Movies.id` = primary key
- `Reviews.movie_id` = foreign key
### 3. Result Behaviour
- Only rows with **matching keys in both tables** are returned.
- Examples:
- Movies without reviews → **excluded**
- Reviews without movies → **excluded**
- A movie with multiple reviews → appears **multiple times**
#### Example:
- Movie **"Don Juan"** with 3 reviews → appears 3 times.
- Movie **"Peter Pan"** with no reviews → does not appear.
### 4. Order of Tables
Both queries return the same result:
`FROM Movies INNER JOIN Reviews`
or
`FROM Reviews INNER JOIN Movies`
- Because INNER JOIN returns only **matching data**, order doesn't change the result.
### 5. Selecting Specific Columns
Instead of retrieving all columns (`SELECT *`), specify only what you need:
```
SELECT Movies.title, Reviews.review
FROM Movies
INNER JOIN Reviews
ON Movies.id = Reviews.movie_id;
```
- Important: Prefix columns with table names to avoid ambiguity.
## 6. INNER JOIN Across Multiple Tables
You can join more than two tables in a single query.
### Example: Get movie title and genres
```
SELECT Movies.title, Genres.name
FROM Movies
INNER JOIN Movies_Genres
  ON Movies.id = Movies_Genres.movie_id
INNER JOIN Genres
  ON Movies_Genres.genre_id = Genres.id
WHERE Movies.title = 'Peter Pan';
```
### How it works:
1. Join **Movies → Movies_Genres** via `movie_id`
2. Join **Movies_Genres → Genres** via `genre_id`
3. Filter for `"Peter Pan"`
## Visual Understanding
- Think of INNER JOIN like the **intersection of two circles (Venn diagram)**:
- Left circle = Movies
- Right circle = Reviews
- Result = only the overlapping middle
## Key Takeaways
- Use **INNER JOIN** to retrieve related data from multiple tables in one query.
- It only returns **matching rows**.
- Always use the `ON` clause to define relationships.
- Specify columns for cleaner results.
- Multiple joins can be chained for more complex relationships.
## Quick Example Summary
```
-- Basic join
SELECT Movies.title, Reviews.review
FROM Movies
INNER JOIN Reviews
ON Movies.id = Reviews.movie_id;
-- Multi-table join
SELECT Movies.title, Genres.name
FROM Movies
INNER JOIN Movies_Genres
  ON Movies.id = Movies_Genres.movie_id
INNER JOIN Genres
  ON Movies_Genres.genre_id = Genres.id;
```
# SQL Aliases (Columns & Tables)
## Column Aliases
- Column aliases allow you to rename output column headers in your query results.
- Useful for making results more readable and user-friendly.
### Syntax
```
SELECT column_name AS alias_name
FROM table_name;
```
- The keyword `AS` is optional:
```
SELECT column_name alias_name
FROM table_name;
```
### Examples
```
SELECT Movies.title AS films, Reviews.review AS reviews
FROM Movies
INNER JOIN Reviews ON Movies.id = Reviews.movie_id;
```
- Without `AS`:
```
SELECT Movies.title films, Reviews.review reviews
FROM Movies
INNER JOIN Reviews ON Movies.id = Reviews.movie_id;
```
### Using Multiple Words in Aliases
- Use quotation marks when the alias contains spaces:
```
SELECT Movies.title AS "Weekly Movies", Reviews.review AS "Weekly Reviews"
FROM Movies
INNER JOIN Reviews ON Movies.id = Reviews.movie_id;
```
## Table Aliases
- Table aliases shorten table names in queries.
- Helpful when:
- Working with long table names
- Writing complex joins
- Improving readability
### Syntax
`FROM table_name alias`
### Example
```
SELECT m.title
FROM Movies m;
```
- Here, `m` is used instead of `Movies`.
## Using Table Aliases in Joins
- Once defined, aliases can be used throughout the query (SELECT, JOIN, WHERE, ORDER BY).
### Example
```
SELECT m.title, r.review
FROM Movies m
INNER JOIN Reviews r ON m.id = r.movie_id;
```
### Example
```
SELECT m.title, g.name
FROM Movies m
INNER JOIN Movies_Genres mg ON m.id = mg.movie_id
INNER JOIN Genres g ON mg.genre_id = g.id;
```
# SQL Outer Joins (LEFT & RIGHT)
## Overview
Outer joins allow you to combine rows from two tables even when there is no match in one of them. They help ensure that you dont lose data from one side of the relationship.
## LEFT OUTER JOIN
### Purpose
- Returns **all records from the left table** (`Movies`)
- Returns **matching records from the right table** (`Reviews`)
- If no match exists, the right-side columns are filled with `NULL`
### Syntax
```
SELECT *
FROM Movies
LEFT OUTER JOIN Reviews
ON Movies.id = Reviews.movie_id;
```
### Key Observations
- Every movie appears in the result
- Movies with multiple reviews appear multiple times
- Movies with **no reviews still appear**, with `NULL` values for review columns
### Example Output Insight
- `Don Juan` appears **3 times** (3 reviews)
- `Peter Pan` appears **once** with no review (NULL values)
## Refining the LEFT JOIN
### Improvements
1. Use table aliases
2. Select only relevant columns
3. Order results
### Example Query
```
SELECT m.title, r.body
FROM Movies m
LEFT OUTER JOIN Reviews r
ON m.id = r.movie_id
ORDER BY r.id;
```
### Result Behaviour
- Movies without reviews (e.g. `Peter Pan`) appear **last** due to ordering by `review id`
## RIGHT OUTER JOIN
### Purpose
- Returns **all records from the right table** (`Reviews`)
- Returns **matching records from the left table** (`Movies`)
- If no match exists, the left-side columns are filled with `NULL`
### Syntax
```
SELECT *
FROM Movies
RIGHT OUTER JOIN Reviews
ON Movies.id = Reviews.movie_id;
```
### Scenario Highlight
- Some `movie_id` values in `Reviews` are set to `NULL`
- These reviews do not link to any movie
### Key Observations
- All reviews are included
- Reviews without a corresponding movie show `NULL` in movie fields
## Refining the RIGHT JOIN
### Example Query
```
SELECT m.title, r.body
FROM Movies m
RIGHT OUTER JOIN Reviews r
ON m.id = r.movie_id
ORDER BY r.id;
```
### Result Behaviour
- All reviews listed
- Reviews with no associated movie have `NULL` titles
## LEFT vs RIGHT JOIN Summary
|Join Type|Includes All From|Missing Matches Show As|
|---|---|---|
|LEFT OUTER JOIN|Left table|NULLs in right columns|
|RIGHT OUTER JOIN|Right table|NULLs in left columns|
## Key Takeaways
- Use **LEFT JOIN** when you care about all records from the first (left) table
- Use **RIGHT JOIN** when you care about all records from the second (right) table
- `NULL` values indicate missing relationships
- Ordering can affect where unmatched rows appear in results
- Outer joins ensure you dont lose unmatched data
- LEFT JOIN = “Show everything from the left”
- RIGHT JOIN = “Show everything from the right”
- Useful for identifying missing relationships and incomplete data

0
Career/Design Patterns.md Executable file → Normal file
View File

0
Career/Devops/CI-CD Example (site visits).md Executable file → Normal file
View File

0
Career/Devops/CI-CD Summary.md Executable file → Normal file
View File

0
Career/Java Portswrigger Test.md Executable file → Normal file
View File

0
Career/Job applications.md Executable file → Normal file
View File

0
Career/MVP + MVT.md Executable file → Normal file
View File

0
Career/Microlise/APIM.md Executable file → Normal file
View File

0
Career/Microlise/ESS ESP/ESP Applications.md Executable file → Normal file
View File

0
Career/Microlise/ESS ESP/ESP Database.md Executable file → Normal file
View File

0
Career/Microlise/ESS ESP/ESP Deploy Stages.md Executable file → Normal file
View File

0
Career/Microlise/ESS ESP/ESP Glossary.md Executable file → Normal file
View File

0
Career/Microlise/ESS ESP/ESP Known Issues and Risks.md Executable file → Normal file
View File

0
Career/Microlise/ESS ESP/ESP Manifest.md Executable file → Normal file
View File

0
Career/Microlise/ESS ESP/ESP OQ.md Executable file → Normal file
View File

0
Career/Microlise/ESS ESP/ESP Pipeline.md Executable file → Normal file
View File

0
Career/Microlise/ESS ESP/ESP Scripts.md Executable file → Normal file
View File

0
Career/Microlise/ESS ESP/ESS ESP Index.md Executable file → Normal file
View File

0
Career/Microlise/ESS ESP/Microlise - ESS.md Executable file → Normal file
View File

0
Career/Microlise/Microlise Assessment.md Executable file → Normal file
View File

0
Career/Microlise/Microlise MOC.md Executable file → Normal file
View File

0
Career/Microlise/Pre work prep.md Executable file → Normal file
View File

0
Career/Microlise/Seb Search Improvements.md Executable file → Normal file
View File

View File

@@ -0,0 +1,801 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Session Stored XSS PENTEST.html</title>
<meta http-equiv="Content-Type" content="text/html;charset=utf-8"/>
</head>
<body>
<h1 id="links">Links:</h1>
<ul>
<li>[[Cross Site Scripting (XSS)]]</li>
</ul>
<h1 id="metadata">Metadata</h1>
<ul>
<li>Name<br />
Understanding Session XSS</li>
<li>Overview<br />
Pages 3334 document an informational “Session stored XSS” finding on
the TMC Schedule Execution Board. The issue is real (unescaped user
input in a JavaScript context) but impact is limited because only the
submitting users session is affected—classic self-XSS, not cross-user
attack.</li>
</ul>
<h2 id="todos">Todos</h2>
<ul class="task-list">
<li><label><input type="checkbox" checked="" />review-finding<br />
Read pages 3334 and map finding to SaveSearchCriteriaToSession +
ScheduleExecutionBoard.aspx flow</label></li>
<li><label><input type="checkbox" checked="" />locate-source<br />
Open TMC Web Portal repo and find session save + inline script render
for date/orderID/time</label></li>
<li><label><input type="checkbox" />remediate-encode<br />
Apply HttpUtility.JavaScriptStringEncode to all session values in
SetupControls() (~1849-1879)</label></li>
<li><label><input type="checkbox" />remediate-validate<br />
Add server-side validation in SaveSearchCriteriaToSession before writing
SEBSessionState</label></li>
<li><label><input type="checkbox" />remediate-retest<br />
Retest with direct POST payload + normal UI search flow on
ScheduleExecutionBoard</label></li>
</ul>
<h1
id="understanding-the-session-stored-xss-finding-pages-3334">Understanding
the Session Stored XSS Finding (Pages 3334)</h1>
<h2 id="where-this-sits-in-the-report">Where this sits in the
report</h2>
<p>The <a
href="d:/_dev/_misc/Pentest-04-26/Microlise%20TMC%20PO%20WA%20April%202026%20v1.0.pdf">Microlise
TMC PO WA April 2026 v1.0.pdf</a> lists <strong>14 findings</strong>
total. Pages 3334 (<a
href="d:/_dev/_misc/Pentest-04-26/33-34.pdf">33-34.pdf</a>) are the last
technical finding before “END OF DOCUMENT”:</p>
<table>
<colgroup>
<col style="width: 10%" />
<col style="width: 89%" />
</colgroup>
<thead>
<tr>
<th>Field</th>
<th>Value</th>
</tr>
</thead>
<tbody>
<tr>
<td>Title</td>
<td><strong>Session stored XSS</strong></td>
</tr>
<tr>
<td>Severity</td>
<td><strong>Informational</strong> (lowest tier; 4 informational
findings in the report)</td>
</tr>
<tr>
<td>Status</td>
<td>Open</td>
</tr>
<tr>
<td>CWE</td>
<td><a href="https://cwe.mitre.org/data/definitions/79.html">CWE-79</a>
— Improper Neutralization of Input</td>
</tr>
<tr>
<td>Environment</td>
<td><code>cert.microlise.com</code> (cert/UAT), path prefix
<code>/PENTEST/TMCWebPortal/</code></td>
</tr>
</tbody>
</table>
<p>Higher-severity items in the same report (SQLi, IDOR, BFLA, etc.) are
separate; this finding is documented as <strong>technically valid but
low business risk</strong>.</p>
<hr />
<h2 id="what-xss-is-general">What XSS is (general)</h2>
<p><strong>Cross-Site Scripting (XSS)</strong> means untrusted data ends
up in a web page in a way the <strong>browser treats as executable
JavaScript</strong>, instead of inert text.</p>
<p>The name “cross-site” is historical: classic attacks trick a
<strong>victim</strong> into loading a page on <strong>your</strong> app
so script runs in <strong>your</strong> origin (stealing session
cookies, performing actions as the user, etc.).</p>
<p>Common types:</p>
<table>
<colgroup>
<col style="width: 15%" />
<col style="width: 45%" />
<col style="width: 39%" />
</colgroup>
<thead>
<tr>
<th>Type</th>
<th>Persistence</th>
<th>Typical delivery</th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>Reflected</strong></td>
<td>Not stored; one-off response</td>
<td>Malicious link/query param</td>
</tr>
<tr>
<td><strong>Stored</strong></td>
<td>Saved server-side (DB, file, session)</td>
<td>Victim loads a normal page later</td>
</tr>
<tr>
<td><strong>DOM-based</strong></td>
<td>Client-side only</td>
<td>Unsafe innerHTML, eval, etc.</td>
</tr>
</tbody>
</table>
<p><strong>Defense in depth:</strong> validate input on the server
(whitelist formats), and <strong>encode output</strong> for the exact
context (HTML, attribute, JavaScript string, URL).</p>
<hr />
<h2 id="what-happened-in-this-finding-tmc-context">What happened in
<em>this</em> finding (TMC context)</h2>
<h3 id="affected-surface-source-located">Affected surface (source
located)</h3>
<table>
<colgroup>
<col style="width: 20%" />
<col style="width: 79%" />
</colgroup>
<thead>
<tr>
<th>Role</th>
<th>Path</th>
</tr>
</thead>
<tbody>
<tr>
<td>Page + inline JS</td>
<td><a
href="d:/_dev/WebPortal/src/code/AmberWebUI/SEB/ScheduleExecutionBoard.aspx">ScheduleExecutionBoard.aspx</a></td>
</tr>
<tr>
<td>WebMethod + page properties</td>
<td><a
href="d:/_dev/WebPortal/src/code/AmberWebUI/SEB/ScheduleExecutionBoard.aspx.cs">ScheduleExecutionBoard.aspx.cs</a></td>
</tr>
<tr>
<td>Session storage</td>
<td><a
href="d:/_dev/WebPortal/src/code/AmberWebUI/SEB/SEBSessionState.cs">SEBSessionState.cs</a></td>
</tr>
</tbody>
</table>
<ul>
<li><strong>Endpoint:</strong> ASP.NET <code>[WebMethod]</code>
<code>SaveSearchCriteriaToSession</code> on
<code>ScheduleExecutionBoard.aspx</code></li>
<li><strong>Parameters:</strong> JSON fields <code>date</code>,
<code>orderID</code>, <code>time</code> (also <code>searchID</code>,
<code>hours</code>, <code>quickSearch</code> in the same flow)</li>
<li><strong>Host (pentest):</strong> <code>cert.microlise.com</code>,
path <code>/PENTEST/TMCWebPortal/SEB/...</code></li>
</ul>
<h3 id="attack-flow-as-tested">Attack flow (as tested)</h3>
<pre class="mermaid"><code>flowchart LR
subgraph submit [Step1_Submit]
A[Tester sends POST directly]
B[SaveSearchCriteriaToSession]
C[Values stored in server session]
end
subgraph render [Step2_Render]
D[User loads ScheduleExecutionBoard.aspx]
E[Server embeds session values in script block]
F[Browser executes unescaped JS]
end
A --&gt; B --&gt; C
C --&gt; D --&gt; E --&gt; F</code></pre>
<ol type="1">
<li><strong>Save:</strong> User (or tester) POSTs JSON to
<code>SaveSearchCriteriaToSession</code>. The app saves search criteria
into the <strong>server-side session</strong>.</li>
<li><strong>Render:</strong> On the next load of
<code>ScheduleExecutionBoard.aspx</code>, those values are written into
the HTML <strong>inside a <code>&lt;script&gt;</code> block</strong>, as
JavaScript string literals.</li>
<li><strong>Bug:</strong> Values are inserted <strong>without JavaScript
string encoding</strong>. A crafted <code>date</code> can <strong>break
out of the string</strong> and run arbitrary JS.</li>
<li><strong>Proof:</strong> Pentesters confirmed execution in the
browser; screenshots in the PDF show the POST and page source.</li>
</ol>
<h3 id="code-path-matches-report-exactly">Code path (matches report
exactly)</h3>
<p><strong>1. Save — no server-side validation</strong></p>
<div class="sourceCode" id="cb2"><pre
class="sourceCode csharp"><code class="sourceCode cs"><span id="cb2-1"><a href="#cb2-1" aria-hidden="true" tabindex="-1"></a><span class="co">// ScheduleExecutionBoard.aspx.cs lines 336-348</span></span>
<span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a><span class="op">[</span>WebMethod<span class="op">]</span></span>
<span id="cb2-3"><a href="#cb2-3" aria-hidden="true" tabindex="-1"></a><span class="kw">public</span> <span class="kw">static</span> <span class="dt">void</span> <span class="fu">SaveSearchCriteriaToSession</span><span class="op">(</span><span class="dt">string</span> searchID<span class="op">,</span> <span class="dt">string</span> orderID<span class="op">,</span> <span class="dt">string</span> date<span class="op">,</span> <span class="dt">string</span> time<span class="op">,</span> <span class="dt">int</span> hours<span class="op">,</span> <span class="dt">bool</span> displayPriorityJourneys<span class="op">,</span> <span class="dt">string</span> quickSearch<span class="op">)</span></span>
<span id="cb2-4"><a href="#cb2-4" aria-hidden="true" tabindex="-1"></a><span class="op">{</span></span>
<span id="cb2-5"><a href="#cb2-5" aria-hidden="true" tabindex="-1"></a> <span class="dt">var</span> sebState <span class="op">=</span> <span class="kw">new</span> <span class="fu">SEBSessionState</span><span class="op">();</span></span>
<span id="cb2-6"><a href="#cb2-6" aria-hidden="true" tabindex="-1"></a> sebState<span class="op">.</span><span class="fu">ComplexSearch</span> <span class="op">=</span> searchID<span class="op">;</span></span>
<span id="cb2-7"><a href="#cb2-7" aria-hidden="true" tabindex="-1"></a> sebState<span class="op">.</span><span class="fu">OrderBy</span> <span class="op">=</span> orderID<span class="op">;</span></span>
<span id="cb2-8"><a href="#cb2-8" aria-hidden="true" tabindex="-1"></a> sebState<span class="op">.</span><span class="fu">SearchDate</span> <span class="op">=</span> date<span class="op">;</span></span>
<span id="cb2-9"><a href="#cb2-9" aria-hidden="true" tabindex="-1"></a> sebState<span class="op">.</span><span class="fu">SearchTime</span> <span class="op">=</span> time<span class="op">;</span></span>
<span id="cb2-10"><a href="#cb2-10" aria-hidden="true" tabindex="-1"></a> <span class="co">// ...</span></span>
<span id="cb2-11"><a href="#cb2-11" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<p><strong>2. Persist — per-user ASP.NET session</strong></p>
<p><a
href="d:/_dev/WebPortal/src/code/AmberWebUI/SEB/SEBSessionState.cs">SEBSessionState.cs</a>
stores values under keys <code>dateID</code>, <code>timeID</code>,
<code>orderByID</code>.</p>
<p><strong>3. Load — on next full page GET</strong></p>
<div class="sourceCode" id="cb3"><pre
class="sourceCode csharp"><code class="sourceCode cs"><span id="cb3-1"><a href="#cb3-1" aria-hidden="true" tabindex="-1"></a><span class="co">// ScheduleExecutionBoard.aspx.cs lines 267-277</span></span>
<span id="cb3-2"><a href="#cb3-2" aria-hidden="true" tabindex="-1"></a><span class="kw">private</span> <span class="dt">void</span> <span class="fu">SetupControls</span><span class="op">()</span></span>
<span id="cb3-3"><a href="#cb3-3" aria-hidden="true" tabindex="-1"></a><span class="op">{</span></span>
<span id="cb3-4"><a href="#cb3-4" aria-hidden="true" tabindex="-1"></a> <span class="dt">var</span> sebState <span class="op">=</span> <span class="kw">new</span> <span class="fu">SEBSessionState</span><span class="op">();</span></span>
<span id="cb3-5"><a href="#cb3-5" aria-hidden="true" tabindex="-1"></a> SessionOrderID <span class="op">=</span> sebState<span class="op">.</span><span class="fu">OrderBy</span><span class="op">;</span></span>
<span id="cb3-6"><a href="#cb3-6" aria-hidden="true" tabindex="-1"></a> SessionDate <span class="op">=</span> sebState<span class="op">.</span><span class="fu">SearchDate</span><span class="op">;</span></span>
<span id="cb3-7"><a href="#cb3-7" aria-hidden="true" tabindex="-1"></a> SessionTime <span class="op">=</span> sebState<span class="op">.</span><span class="fu">SearchTime</span><span class="op">;</span></span>
<span id="cb3-8"><a href="#cb3-8" aria-hidden="true" tabindex="-1"></a> <span class="co">// ...</span></span>
<span id="cb3-9"><a href="#cb3-9" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<p><strong>4. Render — vulnerable inline JavaScript (root
cause)</strong></p>
<div class="sourceCode" id="cb4"><pre
class="sourceCode javascript"><code class="sourceCode javascript"><span id="cb4-1"><a href="#cb4-1" aria-hidden="true" tabindex="-1"></a><span class="co">// ScheduleExecutionBoard.aspx lines 1853-1875</span></span>
<span id="cb4-2"><a href="#cb4-2" aria-hidden="true" tabindex="-1"></a><span class="cf">if</span> (<span class="st">&quot;&lt;%=SessionDate%&gt;&quot;</span>) {</span>
<span id="cb4-3"><a href="#cb4-3" aria-hidden="true" tabindex="-1"></a> <span class="fu">$</span>(<span class="st">&#39;#txtStart&#39;</span>)<span class="op">.</span><span class="fu">val</span>(<span class="st">&quot;&lt;%= SessionDate %&gt;&quot;</span>)<span class="op">;</span></span>
<span id="cb4-4"><a href="#cb4-4" aria-hidden="true" tabindex="-1"></a>}</span>
<span id="cb4-5"><a href="#cb4-5" aria-hidden="true" tabindex="-1"></a><span class="cf">if</span> (<span class="st">&quot;&lt;%=SessionTime%&gt;&quot;</span>) {</span>
<span id="cb4-6"><a href="#cb4-6" aria-hidden="true" tabindex="-1"></a> <span class="fu">$</span>(<span class="st">&#39;#inputtime&#39;</span>)<span class="op">.</span><span class="fu">val</span>(<span class="st">&quot;&lt;%=SessionTime%&gt;&quot;</span>)<span class="op">;</span></span>
<span id="cb4-7"><a href="#cb4-7" aria-hidden="true" tabindex="-1"></a>}</span>
<span id="cb4-8"><a href="#cb4-8" aria-hidden="true" tabindex="-1"></a><span class="cf">if</span> (<span class="st">&quot;&lt;%=SessionOrderID%&gt;&quot;</span>) {</span>
<span id="cb4-9"><a href="#cb4-9" aria-hidden="true" tabindex="-1"></a> <span class="fu">$</span>(orderBySelector <span class="op">+</span> <span class="st">&#39; option[value=&quot;&lt;%=SessionOrderID%&gt;&quot;]&#39;</span>)<span class="op">.</span><span class="fu">attr</span>(<span class="st">&#39;selected&#39;</span><span class="op">,</span> <span class="st">&#39;selected&#39;</span>)<span class="op">;</span></span>
<span id="cb4-10"><a href="#cb4-10" aria-hidden="true" tabindex="-1"></a>}</span></code></pre></div>
<p>Example payload in session:
<code>"); alert(document.domain); //</code></p>
<div class="sourceCode" id="cb5"><pre
class="sourceCode javascript"><code class="sourceCode javascript"><span id="cb5-1"><a href="#cb5-1" aria-hidden="true" tabindex="-1"></a><span class="fu">$</span>(<span class="st">&#39;#txtStart&#39;</span>)<span class="op">.</span><span class="fu">val</span>(<span class="st">&quot;&quot;</span>)<span class="op">;</span> <span class="fu">alert</span>(<span class="bu">document</span><span class="op">.</span><span class="at">domain</span>)<span class="op">;</span> <span class="co">//&quot;);</span></span></code></pre></div>
<p><strong>Related:</strong> <code>QuickSearch</code> at line ~1879 —
fix in the same pass.</p>
<h3 id="why-stored-session-and-self-xss">Why “stored”, “session”, and
“self-XSS”</h3>
<ul>
<li><strong>Stored:</strong> Payload survives page navigation in
<strong>session state</strong>.</li>
<li><strong>Self-XSS:</strong> Only the submitters session is affected;
no normal cross-user path.</li>
<li>Severity <strong>Informational</strong> because threat model is weak
vs shared stored XSS.</li>
</ul>
<h3 id="client-vs-server-validation-gap">Client vs server validation
gap</h3>
<p>Pentesters bypassed browser validation via direct POST. No
server-side validation blocked arbitrary strings.</p>
<hr />
<h2 id="replicating-the-vulnerability-hands-on">Replicating the
vulnerability (hands-on)</h2>
<p>Use this section to <strong>see the bug work</strong> on an
authorized environment (e.g. cert/UAT), then <strong>repeat the same
steps after fixes</strong> and compare outcomes.</p>
<h3 id="prerequisites">Prerequisites</h3>
<table>
<colgroup>
<col style="width: 20%" />
<col style="width: 80%" />
</colgroup>
<thead>
<tr>
<th>Requirement</th>
<th>Detail</th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>Authorization</strong></td>
<td>Pentest scope or internal security test policy only</td>
</tr>
<tr>
<td><strong>Permission</strong></td>
<td><code>Microlise:TMC:SEB:Read</code></td>
</tr>
<tr>
<td><strong>URL</strong></td>
<td>e.g. <code>https://&lt;host&gt;/TMCWebPortal/SEB/ScheduleExecutionBoard.aspx</code></td>
</tr>
<tr>
<td><strong>Tools</strong></td>
<td>Browser + DevTools or Burp Suite</td>
</tr>
<tr>
<td><strong>Build</strong></td>
<td>Before-fix build first; redeploy with remediation for after-fix
runs</td>
</tr>
</tbody>
</table>
<p>Must be logged in (valid session cookie on POST).</p>
<h3 id="what-you-should-observe-before-fix">What you should observe
(before fix)</h3>
<pre class="mermaid"><code>sequenceDiagram
participant You as Tester_browser
participant API as SaveSearchCriteriaToSession
participant Sess as ASP.NET_session
participant Page as ScheduleExecutionBoard_GET
You-&gt;&gt;API: POST JSON with malicious date
API-&gt;&gt;Sess: Store raw date in session
You-&gt;&gt;Page: Reload SEB page
Page-&gt;&gt;You: HTML with unescaped date inside script
You-&gt;&gt;You: alert or other JS runs</code></pre>
<ol type="1">
<li>WebMethod returns HTTP 200.</li>
<li>Payload never went through <code>DateValidation()</code>.</li>
<li>Full page reload → JS runs (e.g. <code>alert</code>).</li>
<li>View Source: payload inside double-quoted JS string, unescaped.</li>
</ol>
<p><strong>Self-XSS:</strong> only your session is poisoned.</p>
<h3 id="step-by-step-reproduction">Step-by-step reproduction</h3>
<p><strong>Step 1 — Baseline (optional)</strong></p>
<ol type="1">
<li>Open SEB, perform a search.</li>
<li>DevTools → Network → <code>SaveSearchCriteriaToSession</code>.</li>
<li>Note POST, <code>application/json</code>, body shape, Cookie
header.</li>
</ol>
<p><strong>Step 2 — Inject via direct POST (bypass UI)</strong></p>
<table>
<thead>
<tr>
<th>Parameter</th>
<th>Suggested test value</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>searchID</code></td>
<td><code>0.X</code></td>
</tr>
<tr>
<td><code>orderID</code></td>
<td><code>0.X</code></td>
</tr>
<tr>
<td><code>date</code></td>
<td><code>"); alert(document.domain);//</code></td>
</tr>
<tr>
<td><code>time</code></td>
<td><code>00:00</code></td>
</tr>
<tr>
<td><code>hours</code></td>
<td><code>24</code></td>
</tr>
<tr>
<td><code>displayPriorityJourneys</code></td>
<td><code>false</code></td>
</tr>
<tr>
<td><code>quickSearch</code></td>
<td><code>""</code></td>
</tr>
</tbody>
</table>
<p><strong>Burp:</strong> Repeater → replace JSON body → send.</p>
<p><strong>Browser console</strong> (on SEB page, same origin):</p>
<div class="sourceCode" id="cb7"><pre
class="sourceCode javascript"><code class="sourceCode javascript"><span id="cb7-1"><a href="#cb7-1" aria-hidden="true" tabindex="-1"></a><span class="fu">fetch</span>(<span class="st">&#39;ScheduleExecutionBoard.aspx/SaveSearchCriteriaToSession&#39;</span><span class="op">,</span> {</span>
<span id="cb7-2"><a href="#cb7-2" aria-hidden="true" tabindex="-1"></a> <span class="dt">method</span><span class="op">:</span> <span class="st">&#39;POST&#39;</span><span class="op">,</span></span>
<span id="cb7-3"><a href="#cb7-3" aria-hidden="true" tabindex="-1"></a> <span class="dt">credentials</span><span class="op">:</span> <span class="st">&#39;include&#39;</span><span class="op">,</span></span>
<span id="cb7-4"><a href="#cb7-4" aria-hidden="true" tabindex="-1"></a> <span class="dt">headers</span><span class="op">:</span> { <span class="st">&#39;Content-Type&#39;</span><span class="op">:</span> <span class="st">&#39;application/json; charset=utf-8&#39;</span> }<span class="op">,</span></span>
<span id="cb7-5"><a href="#cb7-5" aria-hidden="true" tabindex="-1"></a> <span class="dt">body</span><span class="op">:</span> <span class="bu">JSON</span><span class="op">.</span><span class="fu">stringify</span>({</span>
<span id="cb7-6"><a href="#cb7-6" aria-hidden="true" tabindex="-1"></a> <span class="dt">searchID</span><span class="op">:</span> <span class="st">&#39;0.X&#39;</span><span class="op">,</span></span>
<span id="cb7-7"><a href="#cb7-7" aria-hidden="true" tabindex="-1"></a> <span class="dt">orderID</span><span class="op">:</span> <span class="st">&#39;0.X&#39;</span><span class="op">,</span></span>
<span id="cb7-8"><a href="#cb7-8" aria-hidden="true" tabindex="-1"></a> <span class="dt">date</span><span class="op">:</span> <span class="st">&#39;&quot;); alert(document.domain);//&#39;</span><span class="op">,</span></span>
<span id="cb7-9"><a href="#cb7-9" aria-hidden="true" tabindex="-1"></a> <span class="dt">time</span><span class="op">:</span> <span class="st">&#39;00:00&#39;</span><span class="op">,</span></span>
<span id="cb7-10"><a href="#cb7-10" aria-hidden="true" tabindex="-1"></a> <span class="dt">hours</span><span class="op">:</span> <span class="dv">24</span><span class="op">,</span></span>
<span id="cb7-11"><a href="#cb7-11" aria-hidden="true" tabindex="-1"></a> <span class="dt">displayPriorityJourneys</span><span class="op">:</span> <span class="kw">false</span><span class="op">,</span></span>
<span id="cb7-12"><a href="#cb7-12" aria-hidden="true" tabindex="-1"></a> <span class="dt">quickSearch</span><span class="op">:</span> <span class="st">&#39;&#39;</span></span>
<span id="cb7-13"><a href="#cb7-13" aria-hidden="true" tabindex="-1"></a> })</span>
<span id="cb7-14"><a href="#cb7-14" aria-hidden="true" tabindex="-1"></a>})<span class="op">.</span><span class="fu">then</span>(r <span class="kw">=&gt;</span> <span class="bu">console</span><span class="op">.</span><span class="fu">log</span>(<span class="st">&#39;status&#39;</span><span class="op">,</span> r<span class="op">.</span><span class="at">status</span>))<span class="op">;</span></span></code></pre></div>
<p><strong>curl</strong> (replace host, path, cookies):</p>
<div class="sourceCode" id="cb8"><pre
class="sourceCode bash"><code class="sourceCode bash"><span id="cb8-1"><a href="#cb8-1" aria-hidden="true" tabindex="-1"></a><span class="ex">curl</span> <span class="at">-s</span> <span class="at">-o</span> /dev/null <span class="at">-w</span> <span class="st">&quot;%{http_code}&quot;</span> <span class="dt">\</span></span>
<span id="cb8-2"><a href="#cb8-2" aria-hidden="true" tabindex="-1"></a> <span class="at">-X</span> POST <span class="st">&quot;https://&lt;host&gt;/&lt;TMCWebPortal&gt;/SEB/ScheduleExecutionBoard.aspx/SaveSearchCriteriaToSession&quot;</span> <span class="dt">\</span></span>
<span id="cb8-3"><a href="#cb8-3" aria-hidden="true" tabindex="-1"></a> <span class="at">-H</span> <span class="st">&quot;Content-Type: application/json; charset=utf-8&quot;</span> <span class="dt">\</span></span>
<span id="cb8-4"><a href="#cb8-4" aria-hidden="true" tabindex="-1"></a> <span class="at">-H</span> <span class="st">&quot;Cookie: &lt;paste-session-cookies&gt;&quot;</span> <span class="dt">\</span></span>
<span id="cb8-5"><a href="#cb8-5" aria-hidden="true" tabindex="-1"></a> <span class="at">-d</span> <span class="st">&quot;{</span><span class="dt">\&quot;</span><span class="st">searchID</span><span class="dt">\&quot;</span><span class="st">:</span><span class="dt">\&quot;</span><span class="st">0.X</span><span class="dt">\&quot;</span><span class="st">,</span><span class="dt">\&quot;</span><span class="st">orderID</span><span class="dt">\&quot;</span><span class="st">:</span><span class="dt">\&quot;</span><span class="st">0.X</span><span class="dt">\&quot;</span><span class="st">,</span><span class="dt">\&quot;</span><span class="st">date</span><span class="dt">\&quot;</span><span class="st">:</span><span class="dt">\&quot;\\\&quot;</span><span class="st">); alert(document.domain);//</span><span class="dt">\&quot;</span><span class="st">,</span><span class="dt">\&quot;</span><span class="st">time</span><span class="dt">\&quot;</span><span class="st">:</span><span class="dt">\&quot;</span><span class="st">00:00</span><span class="dt">\&quot;</span><span class="st">,</span><span class="dt">\&quot;</span><span class="st">hours</span><span class="dt">\&quot;</span><span class="st">:24,</span><span class="dt">\&quot;</span><span class="st">displayPriorityJourneys</span><span class="dt">\&quot;</span><span class="st">:false,</span><span class="dt">\&quot;</span><span class="st">quickSearch</span><span class="dt">\&quot;</span><span class="st">:</span><span class="dt">\&quot;\&quot;</span><span class="st">}&quot;</span></span></code></pre></div>
<p><strong>Step 3 — Trigger render (stored XSS)</strong></p>
<ol type="1">
<li>Full navigation reload of <code>ScheduleExecutionBoard.aspx</code>
(F5).</li>
<li><code>SetupControls()</code> embeds session <code>date</code>
(~lines 18541855).</li>
</ol>
<p><strong>Step 4 — Confirm</strong></p>
<table>
<colgroup>
<col style="width: 19%" />
<col style="width: 80%" />
</colgroup>
<thead>
<tr>
<th>Check</th>
<th>Before fix (expected)</th>
</tr>
</thead>
<tbody>
<tr>
<td>Popup / console</td>
<td><code>alert(document.domain)</code> runs</td>
</tr>
<tr>
<td>View Source</td>
<td>Literal <code>"); alert(...)</code> inside
<code>$('#txtStart').val("...")</code> unescaped</td>
</tr>
<tr>
<td>Network on reload</td>
<td>Normal GET only; XSS from inline script</td>
</tr>
<tr>
<td>Other users</td>
<td>No effect (different session)</td>
</tr>
</tbody>
</table>
<p><strong>Step 5 — Optional:</strong> malicious <code>time</code> or
<code>orderID</code>.</p>
<p><strong>Step 6 — Clean up:</strong> log out/in or POST valid
date/time.</p>
<h3 id="comparison-matrix-before-vs-after-fixes">Comparison matrix
(before vs after fixes)</h3>
<p>Run the same Steps 24 after each change:</p>
<table>
<colgroup>
<col style="width: 33%" />
<col style="width: 10%" />
<col style="width: 20%" />
<col style="width: 22%" />
<col style="width: 13%" />
</colgroup>
<thead>
<tr>
<th>Observation</th>
<th>Before fix</th>
<th>After encoding only</th>
<th>After validation only</th>
<th>After both</th>
</tr>
</thead>
<tbody>
<tr>
<td>POST malicious <code>date</code> accepted?</td>
<td>Yes (200)</td>
<td>Yes (200)</td>
<td>No / not stored</td>
<td>No</td>
</tr>
<tr>
<td><code>alert</code> on reload?</td>
<td><strong>Yes</strong></td>
<td><strong>No</strong></td>
<td>Depends*</td>
<td><strong>No</strong></td>
</tr>
<tr>
<td>Executable JS in View Source?</td>
<td><strong>Yes</strong></td>
<td><strong>No</strong> (escaped)</td>
<td>Depends*</td>
<td><strong>No</strong></td>
</tr>
<tr>
<td><code>#txtStart</code> shows attack text?</td>
<td>Maybe</td>
<td>Escaped/safe</td>
<td>Default/empty</td>
<td>Default/empty</td>
</tr>
<tr>
<td>Normal UI search + reload works?</td>
<td>Yes</td>
<td>Yes</td>
<td>Yes</td>
<td>Yes</td>
</tr>
</tbody>
</table>
<p>*If only validation: reload may show no XSS without encoding — still
apply both fixes.</p>
<h3 id="why-ui-only-testing-misses-the-bug">Why UI-only testing misses
the bug</h3>
<table>
<colgroup>
<col style="width: 35%" />
<col style="width: 32%" />
<col style="width: 32%" />
</colgroup>
<thead>
<tr>
<th>Path</th>
<th><code>DateValidation()</code> runs?</th>
<th>Payload reaches session?</th>
</tr>
</thead>
<tbody>
<tr>
<td>Click Search in UI</td>
<td>Yes</td>
<td>No (normal typing)</td>
</tr>
<tr>
<td>Direct POST / Burp / fetch</td>
<td><strong>No</strong></td>
<td><strong>Yes</strong></td>
</tr>
</tbody>
</table>
<p>Reproduction <strong>must</strong> use direct POST to match the
pentest.</p>
<h3 id="evidence-to-capture-for-fix-sign-off">Evidence to capture (for
fix sign-off)</h3>
<ol type="1">
<li>Request (POST body with payload).</li>
<li>Screenshot of alert (before) or no alert (after).</li>
<li>View Source snippet around <code>$('#txtStart').val(</code>.</li>
<li>Regression: legitimate date, reload, criteria restored.</li>
</ol>
<h3 id="safety-and-scope">Safety and scope</h3>
<ul>
<li>No production without approval.</li>
<li>Prefer <code>alert(document.domain)</code> over exfiltration
demos.</li>
<li>Self-XSS: coding defect demo, not mass compromise.</li>
</ul>
<hr />
<h2 id="how-to-fix-it">How to fix it</h2>
<p>Use <strong>two layers</strong>: output encoding + server-side
validation.</p>
<h3 id="fix-1-output-encoding-required">Fix 1 — Output encoding
(required)</h3>
<p>File: <a
href="d:/_dev/WebPortal/src/code/AmberWebUI/SEB/ScheduleExecutionBoard.aspx">ScheduleExecutionBoard.aspx</a>,
<code>SetupControls()</code> (~18471884).</p>
<table>
<thead>
<tr>
<th>Line (approx)</th>
<th>Field</th>
<th>Encode</th>
</tr>
</thead>
<tbody>
<tr>
<td>18491850</td>
<td>SessionSearchID</td>
<td>Yes</td>
</tr>
<tr>
<td>18541855</td>
<td>SessionDate</td>
<td>Yes</td>
</tr>
<tr>
<td>18601861</td>
<td>SessionTime</td>
<td>Yes</td>
</tr>
<tr>
<td>18721874</td>
<td>SessionOrderID</td>
<td>Yes</td>
</tr>
<tr>
<td>18781879</td>
<td>QuickSearch</td>
<td>Yes</td>
</tr>
</tbody>
</table>
<p><strong>Before:</strong></p>
<div class="sourceCode" id="cb9"><pre
class="sourceCode javascript"><code class="sourceCode javascript"><span id="cb9-1"><a href="#cb9-1" aria-hidden="true" tabindex="-1"></a><span class="fu">$</span>(<span class="st">&#39;#txtStart&#39;</span>)<span class="op">.</span><span class="fu">val</span>(<span class="st">&quot;&lt;%= SessionDate %&gt;&quot;</span>)<span class="op">;</span></span></code></pre></div>
<p><strong>After:</strong></p>
<div class="sourceCode" id="cb10"><pre
class="sourceCode javascript"><code class="sourceCode javascript"><span id="cb10-1"><a href="#cb10-1" aria-hidden="true" tabindex="-1"></a><span class="fu">$</span>(<span class="st">&#39;#txtStart&#39;</span>)<span class="op">.</span><span class="fu">val</span>(<span class="st">&quot;&lt;%= HttpUtility.JavaScriptStringEncode(SessionDate ?? string.Empty) %&gt;&quot;</span>)<span class="op">;</span></span></code></pre></div>
<p>Encode <code>if</code> guards too, or use code-behind booleans
(<code>HasSessionDate</code>).</p>
<h3 id="fix-2-server-side-input-validation">Fix 2 — Server-side input
validation</h3>
<p>File: <a
href="d:/_dev/WebPortal/src/code/AmberWebUI/SEB/ScheduleExecutionBoard.aspx.cs">ScheduleExecutionBoard.aspx.cs</a>,
<code>SaveSearchCriteriaToSession</code> (~337).</p>
<table>
<thead>
<tr>
<th>Parameter</th>
<th>Validation rule</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>date</code></td>
<td>Same regex as client <code>DateValidation()</code></td>
</tr>
<tr>
<td><code>time</code></td>
<td><code>^[0-2][0-9]:[0-5][0-9]$</code></td>
</tr>
<tr>
<td><code>orderID</code></td>
<td><code>^[0-9]+(\.X)?$</code></td>
</tr>
<tr>
<td><code>searchID</code></td>
<td>Same as <code>orderID</code></td>
</tr>
<tr>
<td><code>hours</code></td>
<td>Clamp 1999</td>
</tr>
</tbody>
</table>
<div class="sourceCode" id="cb11"><pre
class="sourceCode csharp"><code class="sourceCode cs"><span id="cb11-1"><a href="#cb11-1" aria-hidden="true" tabindex="-1"></a><span class="op">[</span>WebMethod<span class="op">]</span></span>
<span id="cb11-2"><a href="#cb11-2" aria-hidden="true" tabindex="-1"></a><span class="kw">public</span> <span class="kw">static</span> <span class="dt">void</span> <span class="fu">SaveSearchCriteriaToSession</span><span class="op">(...)</span></span>
<span id="cb11-3"><a href="#cb11-3" aria-hidden="true" tabindex="-1"></a><span class="op">{</span></span>
<span id="cb11-4"><a href="#cb11-4" aria-hidden="true" tabindex="-1"></a> <span class="kw">if</span> <span class="op">(!</span><span class="fu">IsValidSebDate</span><span class="op">(</span>date<span class="op">)</span> <span class="op">||</span> <span class="op">!</span><span class="fu">IsValidSebTime</span><span class="op">(</span>time<span class="op">)</span></span>
<span id="cb11-5"><a href="#cb11-5" aria-hidden="true" tabindex="-1"></a> <span class="op">||</span> <span class="op">!</span><span class="fu">IsValidQueryComponentId</span><span class="op">(</span>orderID<span class="op">)</span> <span class="op">||</span> <span class="op">!</span><span class="fu">IsValidQueryComponentId</span><span class="op">(</span>searchID<span class="op">))</span></span>
<span id="cb11-6"><a href="#cb11-6" aria-hidden="true" tabindex="-1"></a> <span class="op">{</span></span>
<span id="cb11-7"><a href="#cb11-7" aria-hidden="true" tabindex="-1"></a> <span class="kw">return</span><span class="op">;</span></span>
<span id="cb11-8"><a href="#cb11-8" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
<span id="cb11-9"><a href="#cb11-9" aria-hidden="true" tabindex="-1"></a> <span class="dt">var</span> sebState <span class="op">=</span> <span class="kw">new</span> <span class="fu">SEBSessionState</span><span class="op">();</span></span>
<span id="cb11-10"><a href="#cb11-10" aria-hidden="true" tabindex="-1"></a> <span class="co">// ...</span></span>
<span id="cb11-11"><a href="#cb11-11" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<p><strong>Date regex:</strong></p>
<pre><code>^[0-9]{4}-(((0[13578]|(10|12))-(0[1-9]|[1-2][0-9]|3[0-1]))|(02-(0[1-9]|[1-2][0-9]))|((0[469]|11)-(0[1-9]|[1-2][0-9]|30)))$</code></pre>
<h3 id="fix-3-what-not-to-do">Fix 3 — What not to do</h3>
<ul>
<li>Do not rely on client <code>DateValidation()</code> alone.</li>
<li>Do not use <code>HtmlEncode</code> in JS string literals.</li>
<li>Do not use <code>innerHTML</code>; keep <code>.val()</code>.</li>
</ul>
<h3 id="fix-4-verification-test-plan">Fix 4 — Verification / test
plan</h3>
<p>Master procedure: <strong>Replicating the vulnerability</strong>
section above.</p>
<p><strong>Negative test:</strong></p>
<div class="sourceCode" id="cb13"><pre
class="sourceCode json"><code class="sourceCode json"><span id="cb13-1"><a href="#cb13-1" aria-hidden="true" tabindex="-1"></a><span class="fu">{</span></span>
<span id="cb13-2"><a href="#cb13-2" aria-hidden="true" tabindex="-1"></a> <span class="dt">&quot;searchID&quot;</span><span class="fu">:</span> <span class="st">&quot;0.X&quot;</span><span class="fu">,</span></span>
<span id="cb13-3"><a href="#cb13-3" aria-hidden="true" tabindex="-1"></a> <span class="dt">&quot;orderID&quot;</span><span class="fu">:</span> <span class="st">&quot;0.X&quot;</span><span class="fu">,</span></span>
<span id="cb13-4"><a href="#cb13-4" aria-hidden="true" tabindex="-1"></a> <span class="dt">&quot;date&quot;</span><span class="fu">:</span> <span class="st">&quot;</span><span class="ch">\&quot;</span><span class="st">); alert(1);//&quot;</span><span class="fu">,</span></span>
<span id="cb13-5"><a href="#cb13-5" aria-hidden="true" tabindex="-1"></a> <span class="dt">&quot;time&quot;</span><span class="fu">:</span> <span class="st">&quot;00:00&quot;</span><span class="fu">,</span></span>
<span id="cb13-6"><a href="#cb13-6" aria-hidden="true" tabindex="-1"></a> <span class="dt">&quot;hours&quot;</span><span class="fu">:</span> <span class="dv">24</span><span class="fu">,</span></span>
<span id="cb13-7"><a href="#cb13-7" aria-hidden="true" tabindex="-1"></a> <span class="dt">&quot;displayPriorityJourneys&quot;</span><span class="fu">:</span> <span class="kw">false</span><span class="fu">,</span></span>
<span id="cb13-8"><a href="#cb13-8" aria-hidden="true" tabindex="-1"></a> <span class="dt">&quot;quickSearch&quot;</span><span class="fu">:</span> <span class="st">&quot;&quot;</span></span>
<span id="cb13-9"><a href="#cb13-9" aria-hidden="true" tabindex="-1"></a><span class="fu">}</span></span></code></pre></div>
<p><strong>Pass:</strong> No alert; escaped in source; invalid date not
stored (with Fix 2).</p>
<p><strong>Positive test:</strong> UI search + reload restores
criteria.</p>
<h3 id="files-to-change-summary">Files to change (summary)</h3>
<table>
<colgroup>
<col style="width: 70%" />
<col style="width: 29%" />
</colgroup>
<thead>
<tr>
<th>File</th>
<th>Change</th>
</tr>
</thead>
<tbody>
<tr>
<td><a
href="d:/_dev/WebPortal/src/code/AmberWebUI/SEB/ScheduleExecutionBoard.aspx">ScheduleExecutionBoard.aspx</a></td>
<td><code>JavaScriptStringEncode</code> in
<code>SetupControls()</code></td>
</tr>
<tr>
<td><a
href="d:/_dev/WebPortal/src/code/AmberWebUI/SEB/ScheduleExecutionBoard.aspx.cs">ScheduleExecutionBoard.aspx.cs</a></td>
<td>Validation in <code>SaveSearchCriteriaToSession</code></td>
</tr>
</tbody>
</table>
<p><strong>References:</strong> <a
href="https://owasp.org/www-community/attacks/xss/">OWASP XSS</a>, <a
href="https://portswigger.net/web-security/cross-site-scripting/stored">PortSwigger
Stored XSS</a>, <a
href="https://learn.microsoft.com/en-us/dotnet/api/system.web.httputility.javascriptstringencode">JavaScriptStringEncode</a></p>
<hr />
<h2 id="mental-model-severity-vs-correctness">Mental model: severity vs
correctness</h2>
<table>
<thead>
<tr>
<th>Question</th>
<th>Answer</th>
</tr>
</thead>
<tbody>
<tr>
<td>Real coding flaw?</td>
<td><strong>Yes</strong> (CWE-79)</td>
</tr>
<tr>
<td>Cross-user session hijack?</td>
<td><strong>Not under normal use</strong> (self-XSS)</td>
</tr>
<tr>
<td>Should it still be fixed?</td>
<td><strong>Yes</strong>, as hygiene</td>
</tr>
<tr>
<td>Priority vs SQLi / IDOR?</td>
<td><strong>Much lower</strong> (informational)</td>
</tr>
</tbody>
</table>
<h2 id="code-snippets">Code snippets</h2>
<h3 id="reset">Reset:</h3>
<pre><code>fetch(&#39;ScheduleExecutionBoard.aspx/SaveSearchCriteriaToSession&#39;, {
  method: &#39;POST&#39;,
  credentials: &#39;include&#39;,
  headers: { &#39;Content-Type&#39;: &#39;application/json; charset=utf-8&#39; },
  body: JSON.stringify({
    searchID: &#39;0.X&#39;, orderID: &#39;0.X&#39;,
    date: &#39;2026-05-27&#39;, time: &#39;00:00&#39;, hours: 24,
    displayPriorityJourneys: false, quickSearch: &#39;&#39;
  })
}).then(() =&gt; location.reload());</code></pre>
<h3 id="alert">Alert</h3>
<pre><code>fetch(&#39;ScheduleExecutionBoard.aspx/SaveSearchCriteriaToSession&#39;, {
  method: &#39;POST&#39;,
  credentials: &#39;include&#39;,
  headers: { &#39;Content-Type&#39;: &#39;application/json; charset=utf-8&#39; },
  body: JSON.stringify({
    searchID: &#39;0.X&#39;,
    orderID: &#39;0.X&#39;,
    date: &#39;&quot;+alert(1)+&quot;&#39;,
    time: &#39;00:00&#39;,
    hours: 24,
    displayPriorityJourneys: false,
    quickSearch: &#39;&#39;
  })
}).then(r =&gt; console.log(r.status, r.statusText));</code></pre>
<h3 id="poison-session">Poison Session</h3>
<pre><code>function poisonSession(field, payload) {
  const body = {
    searchID: &#39;0.X&#39;,
    orderID: &#39;0.X&#39;,
    date: &#39;2026-05-27&#39;,
    time: &#39;00:00&#39;,
    hours: 24,
    displayPriorityJourneys: false,
    quickSearch: &#39;&#39;
  };
  body[field] = payload;
  return fetch(&#39;ScheduleExecutionBoard.aspx/SaveSearchCriteriaToSession&#39;, {
    method: &#39;POST&#39;,
    credentials: &#39;include&#39;,
    headers: { &#39;Content-Type&#39;: &#39;application/json; charset=utf-8&#39; },
    body: JSON.stringify(body)
  }).then(r =&gt; console.log(field, r.status, r.statusText));
}</code></pre>
<h3 id="confirm-prompt-alternative-dialog-evidence">Confirm / prompt
(alternative dialog evidence)</h3>
<pre><code>poisonSession(&#39;date&#39;, &#39;&quot;+confirm(&quot;XSS: SEB session poisoned&quot;)+&quot;&#39;);</code></pre>
<h3 id="visible-banner">Visible banner</h3>
<pre><code>poisonSession(&#39;date&#39;, &#39;&quot;+document.body.insertAdjacentHTML(&quot;afterbegin&quot;,&quot;&lt;div style=\\&quot;position:fixed;top:0;left:0;right:0;background:red;color:white;z-index:99999;padding:12px;text-align:center\\&quot;&gt;XSS PoC — arbitrary script executed in SEB context&lt;/div&gt;&quot;)+&quot;&#39;);</code></pre>
</body>
</html>

54
Career/Microlise/Session Stored XSS PENTEST.md Executable file → Normal file
View File

@@ -380,6 +380,60 @@ public static void SaveSearchCriteriaToSession(...)
^[0-9]{4}-(((0[13578]|(10|12))-(0[1-9]|[1-2][0-9]|3[0-1]))|(02-(0[1-9]|[1-2][0-9]))|((0[469]|11)-(0[1-9]|[1-2][0-9]|30)))$
#### Explanation of regex:
##### `SebDateRegex`
`^[0-9]{4}-(((0[13578]|(10|12))-(0[1-9]|[1-2][0-9]|3[0-1]))|(02-(0[1-9]|[1-2][0-9]))|((0[469]|11)-(0[1-9]|[1-2][0-9]|30)))$`
Overall shape: `YYYY-MM-DD` only — four digits, hyphen, month/day with structure checks.
|Part|Meaning|
|---|---|
|`^` / `$`|Whole string must match (no extra characters).|
|`[0-9]{4}-`|Four-digit year, then `-`.|
|31-day months|`(0[13578]\|(10\|12))-(0[1-9]\|[1-2][0-9]\|3[0-1])` — Jan, Mar, May, Jul, Aug, Oct, Dec: day `01``31`.|
|February|`02-(0[1-9]\|[1-2][0-9])` — day `01``29` (no Feb 30/31).|
|30-day months|`(0[469]\|11)-(0[1-9]\|[1-2][0-9]\|30)` — Apr, Jun, Sep, Nov: day `01``30`.|
Matches: `2026-05-27`, `2024-02-29`, `2024-04-30`
Rejects: `2026-13-01`, `not-a-date`, `"); alert(1);//`, empty/null
Note: This is format validation, not a full calendar check. It does not prove the date exists (e.g. `2025-02-30` can match the February branch). That matches the existing client `DateValidation()` in `ScheduleExecutionBoard.aspx` (line 4050).
#####  `SebTimeRegex`
`^[0-2][0-9]:[0-5][0-9]$`
Overall shape: two digits, `:`, two digits — same idea as `HH:mm` in the UI.
|Part|Meaning|
|---|---|
|`[0-2][0-9]`|First hour digit 02, second 09 → allows `00``29` (looser than strict 0023).|
|`:`|Literal colon.|
|`[0-5][0-9]`|Minutes `00``59`.|
Matches: `00:00`, `12:30`, `23:59`
Rejects: `25:99`, `9:00` (needs two hour digits), `"); alert(1);//`
Note: Values like `29:00` match the pattern but are not real clock times; the pentest/UI convention is this simple pattern, not full time-of-day logic.
#####  `QueryComponentIdRegex`
`^[0-9]+(\.X)?$`
Overall shape: one or more digits, optionally followed by `.X` — the values SEB puts on search/order-by dropdowns.
|Part|Meaning|
|---|---|
|`^` / `$`|Whole string only.|
|`[0-9]+`|One or more digits (e.g. `0`, `123`).|
|`(\.X)?`|Optional literal `.X` (shared / external query suffix in combo markup).|
Matches: `0`, `0.X`, `123`, `123.X`
Rejects: `abc`, `0.XY`, `"); alert(1);//`, empty/null
This aligns with how items are built in `BuildSearchForComboBoxItems` / `BuildOrderByComboBoxItems` (e.g. `"0.X"` for “all journeys” / unspecified order-by).
### Fix 3 — What not to do
- Do not rely on client `DateValidation()` alone.

0
Career/Powershell MOC.md Executable file → Normal file
View File

6
Career/Regex.md Executable file → Normal file
View File

@@ -3,4 +3,10 @@ note type:
- theory
date: 2026-06-04
done:
link: https://www.rexegg.com/regex-quickstart.php
---
Regular expressions (regex) are patterns used to match character combinations in strings, offering a powerful way to search and manipulate text that can replace dozens of lines of code. While the syntax can seem complex, understanding core components like **character classes** (e.g., `[0-9]` for digits, `\w` for word characters), **quantifiers** (e.g., `+` for one or more, `*` for zero or more), and **anchors** (e.g., `^` for start, `$` for end) allows for effective pattern matching.
Check out the link, which is really useful in showcasing the rules.
Use: https://regex101.com/ to build and validate.

View File

Before

Width:  |  Height:  |  Size: 270 KiB

After

Width:  |  Height:  |  Size: 270 KiB

View File

Before

Width:  |  Height:  |  Size: 44 KiB

After

Width:  |  Height:  |  Size: 44 KiB

View File

Before

Width:  |  Height:  |  Size: 46 KiB

After

Width:  |  Height:  |  Size: 46 KiB

0
Career/Security/Cross Site Scripting (XSS).md Executable file → Normal file
View File

0
Career/Security/OWASP Top 10.md Executable file → Normal file
View File

0
Career/Security/Output Encoding.md Executable file → Normal file
View File

0
Career/Security/Server-Side Request Forgery (SSRF).md Executable file → Normal file
View File

0
Career/Software Development Methodologies.md Executable file → Normal file
View File

0
Career/Solid Principles.md Executable file → Normal file
View File

0
Career/Test Driven Development.md Executable file → Normal file
View File

0
Career/Windows Services.md Executable file → Normal file
View File

0
Career/XOR.md Executable file → Normal file
View File