You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
sql-inliner is a .NET CLI tool and NuGet library that optimizes SQL Server views by inlining nested views into a single flattened query, optionally stripping unused columns and joins. It parses SQL using Microsoft's ScriptDom (TSql150Parser) and uses the visitor pattern to analyze and transform the AST.
User Types
User Type
Description
Trust Level
Developer/DBA
Runs the CLI tool locally or in CI/CD to optimize SQL views
High — has direct database access
Library Consumer
Uses the NuGet library programmatically in their own application
Library API (view SQL, options) — no DB connection in library mode
Data Classification
Data Type
Classification
Examples
Database Credentials
Sensitive
Connection strings with passwords in config/CLI
View Definitions
Internal
SQL source code from OBJECT_DEFINITION()
Query Statistics
Internal
CPU time, logical reads, execution plans
Environment Metadata
Internal
Machine name, user name (in benchmark reports)
Session Files
Internal
Iteration SQL, logs, benchmark HTML
2. STRIDE Analysis
S — Spoofing
ID
Threat
Attack Path
Likelihood
Impact
Score
Mitigation
S-1
Malicious config file injection
Attacker places a crafted sqlinliner.json in the working directory; tool auto-discovers and loads it
2
3
6
Tool auto-discovers only in CWD. Users should verify CWD before running. No remote config loading.
S-2
Connection string substitution
Attacker replaces config file to redirect DB connections to a malicious server
2
3
6
Config files are local; OS file permissions protect them. Users should not run tool in untrusted directories.
Countermeasures:
Config auto-discovery is limited to the current working directory
No remote configuration loading — all paths are local
Connection strings are validated through SqlConnectionStringBuilder
Library build (ReleaseLibrary) excludes all DB-connected subsystems
T — Tampering
ID
Threat
Attack Path
Likelihood
Impact
Score
Mitigation
T-1
SQL injection via --view-name
User-supplied view name is interpolated into OBJECT_DEFINITION(object_id('...')) without parameterization
2
4
8
Mitigated. Fixed in #93 — now uses Dapper parameterized queries.
T-2
Malicious SQL file via --view-path or config views
Attacker provides a crafted .sql file that contains malicious SQL; tool parses and may deploy it
2
3
6
ScriptDom parses the SQL as a view definition (CREATE VIEW). Deployment only occurs in interactive optimize flow with user confirmation.
T-3
Path traversal in config view paths
Config views dictionary specifies ../../../sensitive.sql to read arbitrary files
2
2
4
Path.GetFullPath() normalizes paths but does not validate containment within config directory. Impact limited to reading files as SQL (would fail parsing).
T-4
Session file tampering
Attacker modifies iteration files between optimize steps to inject SQL
1
3
3
Session files are in a timestamped directory. SHA256 hash comparison detects edits. User confirms before deployment.
T-5
Deployed view tampering via CREATE/DROP
Tool executes CREATE VIEW and DROP VIEW DDL on the target database
2
3
6
Only in validate/verify/optimize subsystems. DROP targets only tool-created views (_Inlined, _Validate, _Original suffixes). Bracketed identifiers prevent injection in DDL.
Bracketed identifiers [schema].[viewName] in DDL statements (QueryRunner, ValidateSession, VerifySession)
Interactive confirmation before deployment in optimize flow
GetViewDefinition() and TryGetRawViewDefinition() use Dapper parameterized queries (fixed in #93)
R — Repudiation
ID
Threat
Attack Path
Likelihood
Impact
Score
Mitigation
R-1
No audit trail for view deployments
Views are deployed (CREATE OR ALTER VIEW) without logging who deployed or when
2
2
4
Session log records operations with timestamps. Git history tracks source changes. SQL Server has its own audit capabilities.
R-2
Validate/verify operations not logged
Batch operations modify database (temporary views) without persistent audit
2
2
4
Validate writes validate-errors.log. Verify cleans up temp views in finally blocks. Operations are transient.
Countermeasures:
Session directory logs all optimize operations with timestamps
Validate writes error logs to output directory
SQL Server's own auditing captures DDL changes
Git tracks all source code changes
I — Information Disclosure
ID
Threat
Attack Path
Likelihood
Impact
Score
Mitigation
I-1
Connection string exposure via CLI arguments
--connection-string visible in process list, shell history, CI/CD logs
3
3
9
Mitigated. Built-in credential store stores credentials in OS keychain (Windows Credential Manager, macOS Keychain, Linux libsecret). Passwords never appear in CLI args, process lists, or shell history.
I-2
Connection strings in config files
sqlinliner.json stores connection strings with embedded passwords; file not gitignored by default
3
3
9
Mitigated. Config files can specify Server=...;Database=... without passwords. Credentials injected at runtime from OS credential store.
I-3
Session files contain view SQL and metadata
Session directories store full view SQL, execution plans, table names, machine/user names
2
2
4
Files are local to the user's machine. Default OS permissions apply. No automatic cleanup.
I-4
Exception messages may leak paths or SQL
Error messages expose file paths and database errors to the user
2
1
2
Acceptable for a CLI tool. Errors are displayed to the authenticated user only.
I-5
Benchmark reports contain environment info
HTML reports include Environment.MachineName, Environment.UserName, database version, table names
2
2
4
Reports are local files. Users should treat them as internal artifacts.
Countermeasures:
Built-in credential store (credentials subcommand) stores credentials in OS keychain — passwords never appear in CLI args or config files
Windows Authentication / Integrated Security eliminates password exposure
ConnectionStringHelper.Resolve() auto-injects stored credentials at runtime
SqlConnectionStringBuilder normalizes connection strings (does not add passwords)
Session files are local with OS-level access control
Gap: No automatic cleanup of session directories
D — Denial of Service
ID
Threat
Attack Path
Likelihood
Impact
Score
Mitigation
D-1
Deeply nested view chains cause stack overflow
Maliciously crafted view definitions with extreme nesting depth cause recursive inlining to fail
1
2
2
ScriptDom parsing has practical limits. Recursive inlining follows actual view references.
D-2
Large view output overwhelms resources
Inlining a view with hundreds of nested references produces extremely large SQL output
2
2
4
This is expected behavior for complex views. Users can limit scope with --view-name.
Connection strings in config files (not gitignored)
9
Mitigated (credential store)
Residual Risks
T-1 (SQL Injection): Fixed in #93. GetViewDefinition() and TryGetRawViewDefinition() now use Dapper parameterized queries instead of string interpolation.
I-1/I-2 (Credential Exposure): Mitigated by built-in credential store (credentials subcommand). Credentials are stored in the OS keychain and auto-injected at runtime. Connection strings in CLI args and config files no longer need embedded passwords.
4. Security Controls Summary
Category
Implementation
Authentication
Delegates to SQL Server authentication (Windows Auth or SQL Auth via connection string)
Authorization
Delegates to SQL Server permissions; tool requires VIEW DEFINITION, SELECT, and optionally CREATE/ALTER/DROP VIEW
SQL output generated by Sql150ScriptGenerator with proper escaping
Secrets Management
Built-in OS credential store (credentials subcommand) for Windows Credential Manager, macOS Keychain, and Linux libsecret; auto-injects stored credentials into connection strings at runtime
Audit Logging
Session logs with timestamps; validate-errors.log for batch operations
Error Handling
Exceptions caught at command level; error messages displayed to user
Dependency Security
CodeQL analysis in CI; no known vulnerable dependencies