sqlmigration-security-review — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited sqlmigration-security-review (Agent Skill) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
Reviews the security-object family of a SQL Server migration — the slice sqlmigration-review dispatches here rather than checking itself. This skill owns 15 checks (J1–J15) covering whether logins, server/database permissions, credentials, certificate/key ownership, and Central Management Server (CMS) registrations will survive a backup/restore or log shipping/Always On AG seeding migration, and what breaks if they don't.
unsupported on target platform, password policy differences, default database missing
explicit GRANT/DENY statements, ownership chains crossing the migration boundary
linked server stored logins
(excluding TDE, which is sqlencryption-review's domain), backup of certificates before cutover
All fix recipes use native T-SQL system views (sys.server_principals, sys.database_principals, sys.credentials), the in-box SqlServer PowerShell module, and the native sp_help_revlogin script — no third-party module is referenced or required.
Accepts any of the following:
platform
.txt/.csv) — see scripts/capture-security-facts.sqlAzure SQL Database"
sp_helplogins text dumps, SSMSGenerate Scripts output for logins/users
Recommended capture (run on the source instance):
SELECT name, type_desc, is_disabled, default_database_name,
SUSER_SID(name) AS sid
FROM sys.server_principals
WHERE type IN ('S','U','G') AND name NOT LIKE '##%';
SELECT dp.name AS user_name, dp.type_desc, sp.name AS login_name
FROM sys.database_principals dp
LEFT JOIN sys.server_principals sp ON dp.sid = sp.sid
WHERE dp.type IN ('S','U','G');
SELECT name, credential_identity FROM sys.credentials;
-- TDE encryptor certs also have is_active_for_begin_dialog = 0, so anti-join the DEK view to drop them
SELECT c.name, c.certificate_id, c.expiry_date, c.pvt_key_encryption_type_desc
FROM sys.certificates c
WHERE NOT EXISTS (SELECT 1 FROM sys.dm_database_encryption_keys dek
WHERE dek.encryptor_thumbprint = c.thumbprint);Trigger: A database user's SID (sys.database_principals.sid) has no matching login SID (sys.server_principals.sid) on the target instance after restore. Severity: Critical Fix: Run ALTER USER [username] WITH LOGIN = [username]; for each orphaned user once the matching login exists on the target, or use sp_help_revlogin's generated script to recreate logins with matching SIDs before the restore completes.
Trigger: Migration plan creates new SQL-authentication logins on the target manually (e.g., via CREATE LOGIN) rather than scripting them from the source with matching SIDs. Severity: Critical Fix: Generate the login-creation script from the source using sp_help_revlogin (in-box system stored procedure, or its documented script form), which preserves the original SID and hashed password — manually re-typing CREATE LOGIN statements produces a new SID and orphans every database user mapped to that login.
Trigger: Source has Windows-authenticated logins/groups, certificate-mapped logins, or asymmetric-key-mapped logins, and the target platform is Azure SQL Database (no Windows Auth support) or otherwise cannot host that login type. Severity: Critical Fix: Map Windows logins to Microsoft Entra ID identities for Azure SQL Database targets; confirm certificate/key-mapped login support on the specific target platform before migrating — see /sqlmigration-review Y8 for the broader Azure platform check.
Trigger: Source logins have CHECK_POLICY/CHECK_EXPIRATION settings that depend on a domain password policy not enforced identically on the target (e.g., target is a workgroup server or Azure SQL Database with no domain policy). Severity: Warning Fix: Re-evaluate each migrated login's CHECK_POLICY/CHECK_EXPIRATION settings explicitly on the target rather than assuming the source's domain policy carries over silently.
Trigger: A login's default_database_name references a database that either was not part of the migration scope or has a different name on the target. Severity: Warning Fix: ALTER LOGIN [loginname] WITH DEFAULT_DATABASE = [target_db_name]; for each affected login after the database has been migrated and renamed (if applicable).
Trigger: Source login is a member of a fixed or user-defined server role (sys.server_role_members), and the migration plan's login-recreation script does not include role membership statements. Severity: Critical Fix: Script ALTER SERVER ROLE [rolename] ADD MEMBER [loginname]; for every server-role membership captured on the source, and run it immediately after login creation on the target.
Trigger: A database user is a member of a database role (sys.database_role_members), and the orphaned-user fix (J1) recreates the user without reassigning role membership. Severity: Warning Fix: Capture sys.database_role_members before migrating and re-run ALTER ROLE [rolename] ADD MEMBER [username]; for each membership after fixing orphaned users.
Trigger: sys.database_permissions shows explicit (non-role-based) GRANT or DENY statements on objects within the migrated database, and the migration plan only scripts logins/users, not explicit permissions. Severity: Warning Fix: Script sys.database_permissions joined to sys.database_principals and object/schema names before migrating, and replay the explicit GRANT/DENY statements after the database and users exist on the target — explicit grants are not implied by role membership and will be silently lost otherwise.
Trigger: A stored procedure or view in the migrated database references objects in a different database via ownership chaining, and that second database is not in the same migration scope or TRUSTWORTHY/ownership chaining settings differ on the target. Severity: Warning Fix: Identify cross-database ownership chains before migrating (sys.sql_expression_dependencies filtered to cross-database references — capture-security-facts.sql Query 11 collects these per database); either migrate both databases together or replace the chain with an explicit permission grant plus a module signing certificate — do not enable TRUSTWORTHY ON as a substitute, since it is a documented security risk.
Trigger: Source has one or more sys.credentials entries (used by proxy accounts, CLR, or external data sources), and the migration plan's script set does not include credential recreation. Severity: Critical Fix: CREATE CREDENTIAL cannot be scripted with the underlying secret intact (SQL Server does not expose stored secrets) — re-enter the credential's secret manually on the target using CREATE CREDENTIAL [name] WITH IDENTITY = '<identity>', SECRET = '<secret>';, sourced from the original secret store, not from the source instance.
Trigger: msdb.dbo.sysproxies references a credential by credential_id, and the migration order creates the proxy before the credential exists on the target. Severity: Warning Fix: Sequence the migration script to create the credential (J10) before the proxy account, and re-map credential_id by name rather than by ID, since IDs are not guaranteed to match across instances.
Trigger: Source has sys.linked_logins mappings (impersonation or stored credentials for a linked server), and the migration plan recreates the linked server definition without the stored login mapping. Severity: Warning Fix: Script sp_addlinkedsrvlogin for each mapping captured in sys.linked_logins, supplying the stored password again manually (it is not exposed by any system view) — see /sqlmigration-objects-review for the rest of the linked server definition migration.
Trigger: Source has objects depending on a certificate (Service Broker, certificate-mapped logins, module-signing certificates) per sys.certificates, and the certificate is not in the migration plan's script set. Severity: Critical Fix: BACKUP CERTIFICATE [certname] TO FILE = '<path>' WITH PRIVATE KEY (FILE = '<path>', ENCRYPTION BY PASSWORD = '<password>'); on the source, then CREATE CERTIFICATE ... FROM FILE ... WITH PRIVATE KEY (...) on the target before the dependent objects are created. This excludes TDE certificates — see /sqlencryption-review for the full TDE certificate migration sequence.
Trigger: Migrated database has sys.symmetric_keys showing a database master key (name = '##MS_DatabaseMasterKey##'), and no BACKUP MASTER KEY step appears in the migration plan. Severity: Critical Fix: OPEN MASTER KEY DECRYPTION BY PASSWORD = '<password>'; BACKUP MASTER KEY TO FILE = '<path>' ENCRYPTION BY PASSWORD = '<password>'; on the source before migrating, then restore it on the target with RESTORE MASTER KEY FROM FILE = '<path>' DECRYPTION BY PASSWORD = '<password>' ENCRYPTION BY PASSWORD = '<newpassword>'; — see /sqlencryption-review for the full DMK/SMK key hierarchy migration sequence if this database uses Always Encrypted or column-level encryption.
Trigger: The migration changes the instance name or the listener name the application connects through, and CMS registrations on the CMS host (managed via SSMS Registered Servers, backed internally by msdb.dbo.sysmanagement_shared_registered_servers) still reference the pre-migration name. Severity: Info Fix: Update the CMS registration's server name via the SSMS Registered Servers GUI — this is the Microsoft-documented mechanism and the one to use by default. Unverified: the underlying msdb.dbo.sysmanagement_shared_registered_servers table and a sp_sysmanagement_update_shared_registered_server procedure are referenced in community documentation of CMS internals, but Microsoft Learn does not publicly document this schema or any T-SQL procedure for scripting CMS registration changes — treat any T-SQL-based update to these objects as unsupported and verify against a non-production CMS host before relying on it, or confirm current behavior against the CMS host's actual schema before scripting.
## sqlmigration-security-review
### Summary
[2-3 sentences: login count, permission complexity, headline risk]
### Critical Issues
[J-checks with Critical severity — each as: **J# — Name**, evidence, impact, fix]
### Warnings
[J-checks with Warning severity]
### Info
[J-checks with Info severity, if any]
### Passed Checks
[J-checks evaluated and not fired]
### Not Assessed
[J-checks that could not be evaluated because the required input was not provided]
### Login/Permission Migration Script Checklist
[Ordered list of native-tool scripts to run: sp_help_revlogin output, role membership,
explicit grants, credentials, certificates, in dependency order]
---
Analyzed by: [model name] · [date/time]--brief — Summary + Critical Issues only--critical-only — Critical Issues onlyWhen --verbose is passed, also write output/sqlmigration-security-review/<timestamp>-J/analysis.md (full report) and trace.md (which facts were available, which J-checks were skipped and why).
facts or capture-script output.
sqlencryption-review's domain; J13/J14cover only the migration-script-sequencing risk, not the encryption posture itself.
/sqlmigration-review for the security-object family — not invokedstandalone for non-migration security review (use sqlencryption-review for that).
Mail) for the rest of the proxy/linked-server definition beyond the stored login (J11/J12)
~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.