Let me rephrase the question, to make sure we are on the same page:
Meta-data for the timestamp type say that it doesn't accept NULL, but if you create a table without specifying nullability you can specify NULL for that column on INSERT. Why?
If you SELECT from the table, you will see that the value isn't null after the INSERT. You have the generated "timestamp" (or rowversion, if you prefer that name). I.e., NULL on INSERT is meaningless, it means that the "default" (so to speak) is used.
One can go into a discussion whether this meta-data property for the timestamp type should reflect whether we can specify null on INSERT or whether we can in the end actually have NULL in that column.
I guess we would have to been present when Sybase designed the system tables some decades ago to be able to know that answer. I wasn't. :-)
So, in short: the column of a timestamp type doesn't allow null in the table, and based on that one can argue that the meta-data is correct.
(As an aside, I first though this was a backward compatibility thing, so I fired up a 6.5 version of SQL Server to test on. And I almost fired up a version 4.2 as well. But then I did a SELECT and it wasn't until then that I noticed that the value wasn't NULL at all.)
Here's the T-SQL I played with (on 2019), FWIW:
USE tempdb
DROP TABLE IF EXISTS myTable;
DROP TYPE IF EXISTS myTypeYesNull;
DROP TYPE IF EXISTS myTypeNoNull;
CREATE TYPE myTypeYesNull FROM int NULL;
CREATE TYPE myTypeNoNull FROM int NOT NULL;
GO
CREATE TABLE myTable (yesNull myTypeYesNull, noNull myTypeNoNull, ts timestamp, sname sysname);
GO
SELECT name, is_nullable FROM sys.types WHERE name IN ('myTypeYesNull', 'myTypeNoNull', 'timestamp', 'sysname')
SELECT
COLUMNPROPERTY(OBJECT_ID('myTable'), 'yesNull', 'AllowsNull') AS yesNull
,COLUMNPROPERTY(OBJECT_ID('myTable'), 'noNull', 'AllowsNull') AS noNull
,COLUMNPROPERTY(OBJECT_ID('myTable'), 'ts', 'AllowsNull') AS ts
,COLUMNPROPERTY(OBJECT_ID('myTable'), 'sname', 'AllowsNull') AS sname;
--The ts column accepts NULL even though table meta-data states differently
INSERT INTO myTable (yesNull, noNull, ts, sname)
VALUES(NULL, 1, NULL, 'x')
SELECT * FROM myTable
----------------------------------------------------------------------
--Code executable on really old versions
DROP TABLE myTable
GO
SELECT name, allownulls FROM systypes WHERE name = 'sysname'
CREATE TABLE myTable(ts timestamp NULL)
GO
--Doesn't fail on 6.5
INSERT INTO myTable(ts) VALUES(null)
SELECT * FROM myTable