ΤΕΥΧΟΣ 024  ·  28 ΟΚΤΩΒΡΙΟΥ 2026 RSS
CodeCity
ΑΣΦΑΛΕΙΑ № 0024

zizmor: η ασφάλεια των workflows ελέγχεται πριν τρέξει ο κώδικας

Το zizmor είναι στατικός αναλυτής ασφαλείας για αρχεία CI/CD — GitHub Actions, Dependabot, pre-commit. Διαβάζει τα YAML πριν εκτελεστεί οτιδήποτε, εντοπίζει μονοπάτια επίθεσης και τρέχει offline εξ ορισμού, χωρίς λογαριασμό και χωρίς δίκτυο. Είναι ένα έτοιμο δυαδικό, με μηδέν εξαρτήσεις Python, μηδέν tokens στο μοντέλο και μηδέν ευρώ. Στη δοκιμή μας, ένα workflow 11 γραμμών με σκόπιμα λάθη έβγαλε πέντε ευρήματα και κωδικό εξόδου 14 σε 0,18 δευτερόλεπτα.

zizmor: η ασφάλεια των workflows ελέγχεται πριν τρέξει ο κώδικας

Τι κάνει

Κάθε φορά που ανεβάζεις κώδικα στο GitHub, κάποια αρχεία YAML αποφασίζουν τι θα τρέξει, με ποια δικαιώματα και με ποια μυστικά. Αυτά είναι τα workflows του GitHub Actions. Είναι ο αυτόματος μηχανισμός που χτίζει, δοκιμάζει και δημοσιεύει την εφαρμογή σου. Το πρόβλημα είναι ότι τα ίδια αρχεία είναι και επιφάνεια επίθεσης. Ένα λάθος σε μία γραμμή μπορεί να δώσει σε ξένο κώδικα πρόσβαση στα κλειδιά σου, ή να εκτελέσει εντολή που έγραψε κάποιος έξω από την ομάδα σου.

Το zizmor διαβάζει αυτά τα αρχεία και ψάχνει τέτοια λάθη. Δεν τρέχει το workflow. Δεν στέλνει τίποτα πουθενά. Δεν ζητά λογαριασμό. Κάνει στατική ανάλυση: κοιτάζει το κείμενο, καταλαβαίνει τη δομή του, και συγκρίνει ό,τι βλέπει με γνωστά μοτίβα κακής πρακτικής. Με άλλα λόγια, σου δείχνει το πρόβλημα πριν προλάβει να γίνει ζημιά.

Οι κατηγορίες που πιάνει είναι συγκεκριμένες και έχουν ονόματα. Το template injection: όταν ένα μήνυμα ή τίτλος από έξω μπαίνει απευθείας μέσα σε εντολή κελύφους, ο εισβολέας μπορεί να γράψει τη δική του εντολή. Το unpinned uses: όταν καλείς μία ενέργεια με ετικέτα όπως v4 αντί για πλήρες commit hash, και η ετικέτα αλλάξει χέρια. Το dangerous triggers: όταν ένα workflow ακούει σε συμβάν που φέρνει κώδικα από εξωτερικό fork, όπως το pull_request_target. Το excessive permissions: όταν το workflow ζητά περισσότερα δικαιώματα από όσα του χρειάζονται. Και το artipacked: όταν το checkout αφήνει τα διαπιστευτήρια μέσα στο αντίγραφο και αυτά καταλήγουν σε artifact.

Καμία από αυτές τις κατηγορίες δεν είναι θεωρητική. Είναι ο τρόπος που έχουν συμβεί πραγματικές παραβιάσεις σε δημόσια αποθετήρια. Το εργαλείο δεν σου ζητά να καταλάβεις όλη τη θεωρία από την πρώτη μέρα. Σου δίνει το εύρημα, τον κανόνα, και συχνά μία πρόταση διόρθωσης.

Ένα σημείο που πρέπει να ξεκαθαρίσουμε αμέσως: το zizmor δεν είναι διακομιστής MCP. Δεν μιλάει με το μοντέλο, δεν φορτώνει σχήμα εργαλείων, δεν πιάνει χώρο σε καμία συνεδρία. Είναι εργαλείο γραμμής εντολών. Το τρέχεις από το κέλυφος, διαβάζει αρχεία, τυπώνει αποτελέσματα, βγαίνει. Θα το ξαναπούμε στην ενότητα της χρήσης, γιατί η διάκριση αλλάζει τον τρόπο που το ενσωματώνεις στη ροή σου.

Το project συντηρείται από την ομάδα zizmorcore. Το αποθετήριο ζει από τις 19 Αυγούστου 2024 και έχει σήμερα 6.804 αστέρια, 274 forks και άδεια MIT. Η τελευταία του δραστηριότητα είναι σήμερα, 28 Οκτωβρίου 2026. Έχει χορηγούς τους Grafana Labs, Trail of Bits και Kusari — γεγονός που δείχνει ότι δεν είναι ένα πρόχειρο script κάποιου Σαββατοκύριακου (αποθετήριο).

Στο PyPI η τελευταία σταθερή έκδοση είναι η 1.31.1, δημοσιευμένη στις 15 Οκτωβρίου 2026, με πεδίο upload_time του wheel — όχι άλλο πεδίο, γιατί τα πακέτα συχνά δείχνουν διαφορετικές ημερομηνίες αν κοιτάξεις λάθος μεταδεδομένο. Υπάρχει και μία 1.32.0-rc1 από τις 23 Οκτωβρίου 2026, δηλαδή προέκδοση μία εβδομάδα πριν (PyPI).

Για ποιον είναι

Για όποιον έχει workflow στο GitHub και δεν το έχει διαβάσει ποτέ γραμμή προς γραμμή. Αυτό περιλαμβάνει σχεδόν όλους όσους χρησιμοποιούν Actions, από ομάδες με δέκα αποθετήρια μέχρι κάποιον που έστησε το πρώτο του CI πριν από δύο εβδομάδες.

Ο ερασιτέχνης κερδίζει το πιο απλό: μία εντολή, μία λίστα με λάθη γραμμένα σε κατανοητή γλώσσα, και συχνά αυτόματη διόρθωση. Δεν χρειάζεται να ξέρει τι είναι το pull_request_target για να καταλάβει ότι το workflow του ακούει σε εξωτερικά pull requests και τυπώνει τον τίτλο τους μέσα σε εντολή. Το εργαλείο του το λέει με λόγια.

Ο επαγγελματίας κερδίζει κάτι πιο ακριβές: έναν φραγμό που μπορεί να μπει στο CI και να αποτύχει το build όταν κάποιος προσθέσει επικίνδυνη γραμμή. Δεν είναι εργαλείο για να αντικαταστήσει την κρίση του. Είναι εργαλείο για να μη χαθεί η κρίση μέσα σε ένα diff πενήντα γραμμών.

Λάμπει όταν τα workflows σου είναι πολλά ή όταν τα αγγίζουν πολλά χέρια. Εκεί το ανθρώπινο μάτι κουράζεται, και μία ετικέτα v4 αντί για hash περνά απαρατήρητη.

Δεν είναι για σένα αν δεν χρησιμοποιείς GitHub Actions καθόλου. Δεν είναι επίσης για σένα αν θέλεις εργαλείο που να αποδεικνύει ότι ένα workflow είναι ασφαλές. Το zizmor δείχνει λάθη γνωστών μοτίβων. Δεν εκδίδει πιστοποιητικό ασφαλείας.

Εγκατάσταση

Ο εγκαταστάτης είναι πακέτο Python, αλλά το πρόγραμμα που εκτελείς είναι προμεταφρασμένο δυαδικό. Η Python χρειάζεται μόνο για να κατέβει και να τοποθετηθεί το αρχείο. Μετά την εγκατάσταση, το zizmor τρέχει χωρίς Python. Αυτό είναι σημαντικό: δεν προσθέτεις μία ακόμα γλώσσα στη μηχανή σου για να κάνεις μία δουλειά που κρατά δέκα δευτερόλεπτα.

Ο εγκαταστάτης ζητά Python 3.11 ή νεότερη. Το πεδίο requires_dist του πακέτου στο PyPI είναι κενό — μηδέν εξαρτήσεις Python. Δεν τραβά βιβλιοθήκες, δεν χτίζει δέντρο πακέτων, δεν αφήνει τίποτα πίσω του πέρα από το ίδιο το δυαδικό.

Η δοκιμασμένη διαδρομή, από οποιονδήποτε φάκελο:

uv tool install zizmor

Το uv εγκαθιστά το εργαλείο σε απομονωμένο περιβάλλον και προσθέτει την εντολή zizmor στο PATH. Δεν χρειάζεται εικονικό περιβάλλον, δεν χρειάζεται ενεργοποίηση. Αν έχεις ήδη uv, είναι μία εντολή και τελείωσες.

Ο κατασκευαστής τεκμηριώνει κι άλλους δρόμους: Homebrew, cargo install από πηγή, και απευθείας δυαδικό από τις εκδόσεις. Αυτό είναι ισχυρισμός κατασκευαστή. Εμείς τρέξαμε μόνο τη διαδρομή του uv, και δεν θα σου δώσω οδηγίες για βήματα που δεν εκτέλεσα.

Χρήση σε κάθε LLM

Εδώ ισχύει ο ίδιος κανόνας όπως σε κάθε εργαλείο γραμμής εντολών. Δεν δηλώνεις διακομιστή. Δεν γράφεις ρύθμιση mcpServers. Δεν κάνεις επανεκκίνηση για να σε δει ο βοηθός. Το zizmor δεν είναι MCP server, και αν του φορέσεις σχήμα διακομιστή θα γράψεις ψέμα.

Αυτό που κάνεις είναι να το καλείς από το κέλυφος, είτε πριν αγγίξεις ένα workflow είτε μέσα στο CI ως φραγμό. Η ίδια εντολή δουλεύει παντού, γιατί δεν εξαρτάται από τον βοηθό. Αυτό είναι το πλεονέκτημα: δεν χάνεις την επένδυση όταν αλλάζεις εργαλείο.

Από τη ρίζα του αποθετηρίου σου:

zizmor .github/workflows/

Αυτή η εντολή διαβάζει όλα τα αρχεία του φακέλου και τυπώνει τα ευρήματα. Αν θέλεις να διορθώσει ό,τι διορθώνεται μόνο του, σε ένα συγκεκριμένο αρχείο:

zizmor --fix .github/workflows/ci.yml

Πριν αφήσεις έναν βοηθό να γράψει ή να αλλάξει workflow, ο φραγμός είναι απλός: τρέχεις πρώτα το zizmor, βλέπεις τι λέει, και μόνο τότε προχωράς. Το ίδιο ισχύει και αντίστροφα — αφού ο βοηθός τελειώσει, ξανατρέχεις τον έλεγχο. Δεν χρειάζεται να του εξηγήσεις τι είναι το zizmor. Του δίνεις την εντολή και τον κωδικό εξόδου.

Claude Code

Γράφεις τη σύμβαση στο CLAUDE.md: πριν αλλάξεις workflow, τρέξε zizmor. Και αν θέλεις να το κάνεις εσύ χειροκίνητα, από τη ρίζα:

zizmor .github/workflows/

Codex CLI

Το ίδιο σχήμα, σε αρχείο AGENTS.md. Καμία ενότητα ρυθμίσεων, μόνο η σύμβαση και η εντολή:

zizmor .github/workflows/

Cursor

Και εδώ μία οδηγία στους κανόνες του project, χωρίς δήλωση διακομιστή. Για χειροκίνητο έλεγχο:

zizmor .github/workflows/

Στο CI

Εδώ είναι η πιο δυνατή χρήση, γιατί ο κωδικός εξόδου γίνεται φραγμός. Προσθέτεις ένα βήμα πριν το build:

zizmor .github/workflows/

Αν το βήμα βγει με 14, το pipeline σταματά. Αν βγει με 0, προχωρά. Έτσι κανείς δεν μπορεί να περάσει επικίνδυνη αλλαγή χωρίς να τη δει το εργαλείο. Δεν χρειάζεται δήλωση διακομιστή ούτε εδώ· είναι απλή εντολή κελύφους.

Πού κερδίζει, πού χάνει

Κερδίζει πρώτα στο ότι δεν θέλει τίποτα. Δεν θέλει λογαριασμό, κλειδί, σύνδεση, ρύθμιση, αρχείο config. Το τρέχεις και σου απαντά. Αυτό είναι σπάνιο σε εργαλεία ασφαλείας, που συνήθως ζητούν ενσωμάτωση σε πλατφόρμα ή σύνδεση με υπηρεσία.

Κερδίζει στο ότι τρέχει offline εξ ορισμού. Το τυπώνει μόνο του στην εκτέλεση: «zizmor is running in offline mode by default; some audits and auto-fixes will not be available». Δηλαδή δεν στέλνει τα αρχεία σου πουθενά. Αυτό έχει σημασία για εταιρικά περιβάλλοντα όπου το δίκτυο είναι περιορισμένο, αλλά και για οποιονδήποτε δεν θέλει τα ονόματα των εσωτερικών του ροών σε ξένο διακομιστή.

Κερδίζει στην ταχύτητα. Στη δοκιμή μας, η ανάλυση ενός workflow 11 γραμμών πήρε 0,18 δευτερόλεπτα. Αυτό σημαίνει ότι μπορεί να μπει σε κάθε commit χωρίς να το καταλάβει κανείς.

Κερδίζει στον κωδικό εξόδου. Το 0 σημαίνει καθαρό. Το 13 σημαίνει μόνο προειδοποιήσεις. Το 14 σημαίνει σφάλματα. Αυτή η τριχοτόμηση είναι σπάνια και χρήσιμη: μπορείς να αποφασίσεις αν θέλεις να σπάσεις το build στις προειδοποιήσεις ή μόνο στα σφάλματα. Ο φραγμός είναι δικός σου, όχι του εργαλείου.

Κερδίζει και στη διόρθωση. Δύο από τα πέντε ευρήματα της δοκιμής διορθώθηκαν αυτόματα με –fix. Δεν λύνει όλα τα προβλήματα, αλλά σου κόβει τον κόπο για τα μηχανικά.

Τώρα πού χάνει.

Πρώτο, είναι στατικός αναλυτής. Διαβάζει κείμενο. Δεν εκτελεί το workflow, δεν βλέπει τι κάνει στην πράξη, δεν ξέρει αν μία ενέργεια συμπεριφέρεται όπως υπόσχεται. Μπορεί να βρει ένα μοτίβο γνωστό, αλλά δεν μπορεί να σου εγγυηθεί ότι δεν υπάρχει άλλο, άγνωστο. Η κάλυψη είναι τόσο καλή όσο οι κανόνες που ξέρει.

Δεύτερο, η κάλυψη μπορεί να αλλάξει σε online λειτουργία. Στην online λειτουργία κάποια audits τραβούν μεταδεδομένα ενεργειών από το GitHub. Ο κατασκευαστής λέει ότι είναι προαιρετικό. Εμείς δουλέψαμε offline. Δεν δοκιμάσαμε την online, οπότε δεν ξέρουμε πόσα περισσότερα βλέπει ή πόσα λιγότερα. Αυτό είναι επιφύλαξη, όχι μειονέκτημα: το εργαλείο είναι χρήσιμο και offline.

Τρίτο, θέλει εξοικείωση με YAML για να διορθώσεις ό,τι δεν διορθώνεται μόνο του. Το εύρημα έρχεται με εξήγηση, αλλά η αλλαγή στο αρχείο παραμένει δική σου δουλειά.

Και η έντιμη επιφύλαξη που δεν πρέπει να κρύψουμε: ένα εργαλείο ασφαλείας δεν κάνει το workflow ασφαλές μόνο του. Δείχνει τα λάθη, δεν τα εξαφανίζει. Αν κάποιος θέλει να βάλει επικίνδυνη γραμμή, μπορεί να βρει τρόπο που ο κανόνας δεν πιάνει. Το zizmor μειώνει την επιφάνεια, δεν την εκμηδενίζει.

Δοκιμή

Έγραψα ένα workflow 11 γραμμών επίτηδες γεμάτο λάθη. Είχε pull_request_target ως trigger, ένα βήμα run που τύπωνε το github.event.pull_request.title, και ένα actions/checkout@v4 χωρίς καρφίτσωμα σε hash. Δηλαδή τρία από τα πιο κλασικά σφάλματα μαζί.

Έτρεξα την εντολή από τη ρίζα του αποθετηρίου:

zizmor .github/workflows/

Βγήκε με κωδικό εξόδου 14 σε 0,18 δευτερόλεπτα. Πέντε ευρήματα, με το σωστό χρώμα στο τερματικό: template-injection με υψηλή βεβαιότητα και αυτόματη διόρθωση, unpinned-uses με υψηλή, dangerous-triggers με μέτρια, excessive-permissions με μέτρια, και artipacked με χαμηλή και αυτόματη διόρθωση.

Μετά δοκίμασα το –fix στο ίδιο αρχείο:

zizmor --fix .github/workflows/ci.yml

Διόρθωσε μόνο του τα δύο που είχαν αυτόματη διόρθωση. Τα υπόλοιπα τρία έμειναν για ανθρώπινο χέρι. Αυτό είναι σωστό: δεν περιμένεις από ένα εργαλείο να ξέρει αν θέλεις να αλλάξεις trigger ή δικαιώματα.

Και μετά το καθαρό. Έφτιαξα ένα workflow χωρίς κανένα από αυτά τα λάθη και το έτρεξα. Βγήκε με κωδικό εξόδου 0 και τύπωσε «No findings to report. Good job!». Δηλαδή ο φραγμός δουλεύει και προς τις δύο κατευθύνσεις: σταματά όταν υπάρχει πρόβλημα, περνά όταν δεν υπάρχει.

Τι δεν μέτρησα, και το λέω. Δεν μέτρησα μνήμη. Δεν υπάρχει αξιόπιστο εργαλείο στο κέλυφος που χρησιμοποιώ για να δώσω νούμερο που να στέκει, και ένα νούμερο από εκτίμηση θα ήταν επινόηση. Δεν δοκίμασα την online λειτουργία. Όποιο νούμερο δεν αναφέρεται εδώ, δεν είναι δικό μας.

Τα νούμερα του αποθετηρίου — 6.804 αστέρια, 274 forks, άδεια MIT, τελευταίο push 28 Οκτωβρίου 2026, πρώτη δημιουργία 19 Αυγούστου 2024 — και τα νούμερα του PyPI — 1.31.1 στις 15 Οκτωβρίου 2026, 1.32.0-rc1 στις 23 Οκτωβρίου 2026 — είναι από την έρευνά μας, όπως τα δίνουν το GitHub και το PyPI.

Τι κοστίζει

Το μοντέλο. Δικό μας νούμερο: μηδέν tokens. Το zizmor δεν είναι διακομιστής MCP, δεν φορτώνει σχήμα εργαλείων, δεν πιάνει χώρο σε καμία συνεδρία. Δεν πληρώνεις τίποτα στο πλαίσιο του βοηθού, είτε το χρησιμοποιείς είτε όχι.

Το τοπικό αποτύπωμα. Δικό μας νούμερο: το wheel για Windows είναι 9,03 MB, δηλαδή 9.029.164 bytes. Το εγκατεστημένο εκτελέσιμο είναι 24,9 MB στον δίσκο, δηλαδή 24.859.648 bytes. Μηδέν εξαρτήσεις Python. Καμία διεργασία που μένει ανοιχτή μετά την εκτέλεση. Μνήμη δεν μέτρησα, για τον λόγο που εξήγησα.

Σε χρήμα, μηδέν. Άδεια MIT, χωρίς κλειδί, χωρίς υπηρεσία, χωρίς λογαριασμό, offline από προεπιλογή. Δεν υπάρχει πληρωμένο επίπεδο και δεν υπάρχει τηλεμετρία που να ξέρουμε.

Ισχυρισμός κατασκευαστή, όχι δικό μας νούμερο: ότι η online λειτουργία είναι προαιρετική και ότι κάποια audits τραβούν μεταδεδομένα ενεργειών από το GitHub. Αυτό το διαβάζουμε στην τεκμηρίωση και το είδαμε στο μήνυμα της offline λειτουργίας. Δεν το δοκιμάσαμε.

Ετυμηγορία

Score: 8.7/10.

Το zizmor λύνει ένα πρόβλημα που οι περισσότεροι δεν ξέρουν ότι έχουν: τα workflows τους είναι κώδικας με δικαιώματα, και κανείς δεν τα διαβάζει. Το λύνει χωρίς λογαριασμό, χωρίς δίκτυο, χωρίς εξαρτήσεις, με μία εντολή. Στη δοκιμή μας: πέντε ευρήματα σε 0,18 δευτερόλεπτα, κωδικός εξόδου 14, δύο αυτόματες διορθώσεις, και exit 0 σε καθαρό αρχείο.

Τους υπόλοιπους βαθμούς τους κρατά ή τους χάνει για τρεις λόγους. Είναι στατικός αναλυτής, άρα βλέπει μοτίβα και όχι συμπεριφορά. Η κάλυψη μπορεί να αλλάξει σε online λειτουργία, την οποία δεν δοκιμάσαμε. Και δεν κάνει το workflow ασφαλές μόνο του — δείχνει τα λάθη, δεν τα εξαφανίζει.

Πού το προτείνουμε χωρίς δισταγμό: σε κάθε αποθετήριο με GitHub Actions, ως βήμα πριν το build και ως συνήθεια πριν αγγίξεις ένα workflow. Εκεί είναι ο φθηνότερος φραγμός ασφαλείας που μπορείς να βάλεις σήμερα.

Πηγές: αποθετήριο https://github.com/zizmorcore/zizmor · τεκμηρίωση ελέγχων https://docs.zizmor.sh/audits/ · πακέτο PyPI https://pypi.org/project/zizmor/